测试 测试 #4
20
Routes.js
|
|
@ -1,6 +1,6 @@
|
|||
// import app from './src/App'
|
||||
import app from './src/App'
|
||||
// import users from './src/forge/users/Index';
|
||||
// import Detail from "./src/forge/Main/Detail";
|
||||
import Detail from "./src/forge/Main/Detail";
|
||||
// import Information from "./src/forge/Information/index"
|
||||
// import NewsDetail from './src/forge/Information/Pages/newsDetail';
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ export default [
|
|||
{
|
||||
key:"detail",
|
||||
path: "/:owner/:projectsId",
|
||||
// component: app,
|
||||
component: app,
|
||||
}
|
||||
];
|
||||
|
||||
|
|
@ -26,24 +26,34 @@ export const deepRoutes = [
|
|||
{
|
||||
key: "zoneNews",
|
||||
path: "/zone/:deptId/newdetail/:id",
|
||||
onlyHead: true,
|
||||
// component: NewsDetail
|
||||
},
|
||||
{
|
||||
key: "zone",
|
||||
path: "/zone/:deptId",
|
||||
onlyHead: true,
|
||||
// component: Information
|
||||
},
|
||||
{
|
||||
key: "detailBranch",
|
||||
path: "/:owner/:projectsId/tree/:branchName",
|
||||
onlyHead: false,
|
||||
component: Detail,
|
||||
},
|
||||
{
|
||||
key: "detail",
|
||||
path: "/:owner/:projectsId",
|
||||
// component: Detail,
|
||||
onlyHead: false,
|
||||
component: Detail,
|
||||
},
|
||||
{
|
||||
key: "owner",
|
||||
path: "/:owner",
|
||||
onlyHead: true,
|
||||
// component: Detail,
|
||||
}
|
||||
]
|
||||
|
||||
// 不进行组织或个人判断
|
||||
export const specialRoute = ["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", "undefined", "admins", "oauth", "competitions"]
|
||||
export const specialRoute = ["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", "undefined", "admins", "oauth", "competitions", "hiagent"]
|
||||
|
|
@ -159,12 +159,13 @@ const serverConfig = {
|
|||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
{
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: {
|
||||
publicPath,
|
||||
},
|
||||
},
|
||||
'isomorphic-style-loader',
|
||||
// {
|
||||
// loader: MiniCssExtractPlugin.loader,
|
||||
// options: {
|
||||
// publicPath,
|
||||
// },
|
||||
// },
|
||||
{
|
||||
loader: require.resolve("css-loader"),
|
||||
options: {
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"nvm": "0.0.4",
|
||||
"object-assign": "4.1.1",
|
||||
"papaparse": "^5.3.2",
|
||||
"pinyin": "^4.0.0-alpha.0",
|
||||
"postcss-flexbugs-fixes": "3.2.0",
|
||||
"promise": "8.0.1",
|
||||
"prop-types": "^15.6.1",
|
||||
|
|
@ -158,6 +159,7 @@
|
|||
"analyz": "NODE_ENV=production npm_config_report=true npm run build",
|
||||
"dev": "npm-run-all --parallel dev:**",
|
||||
"dev:server": "cross-env NODE_ENV=dev nodemon --exec babel-node \"./buildserver/bundle.js\" --watch config --watch server",
|
||||
"test:build:server": "cross-env NODE_ENV=localtest webpack --config config/webpack.server.js",
|
||||
"dev:build:server": "cross-env NODE_ENV=dev webpack --config config/webpack.server.js",
|
||||
"pm2": "pm2 start pm2.json"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2522,7 +2522,6 @@ _extend(KRange, {
|
|||
return self;
|
||||
},
|
||||
dump : function() {
|
||||
console.log('--------------------');
|
||||
console.log(this.startContainer.nodeType == 3 ? this.startContainer.nodeValue : this.startContainer, this.startOffset);
|
||||
console.log(this.endContainer.nodeType == 3 ? this.endContainer.nodeValue : this.endContainer, this.endOffset);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2340181 */
|
||||
src: url('iconfont.woff2?t=1686823554834') format('woff2'),
|
||||
url('iconfont.woff?t=1686823554834') format('woff'),
|
||||
url('iconfont.ttf?t=1686823554834') format('truetype');
|
||||
src: url('iconfont.woff2?t=1726630002422') format('woff2'),
|
||||
url('iconfont.woff?t=1726630002422') format('woff'),
|
||||
url('iconfont.ttf?t=1726630002422') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
|
|
@ -13,6 +13,58 @@
|
|||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-gongxianquequan:before {
|
||||
content: "\e979";
|
||||
}
|
||||
|
||||
.icon-xuanzhong5:before {
|
||||
content: "\e97a";
|
||||
}
|
||||
|
||||
.icon-big-circle:before {
|
||||
content: "\e978";
|
||||
}
|
||||
|
||||
.icon-gitee:before {
|
||||
content: "\e974";
|
||||
}
|
||||
|
||||
.icon-gitea:before {
|
||||
content: "\e975";
|
||||
}
|
||||
|
||||
.icon-coding:before {
|
||||
content: "\e976";
|
||||
}
|
||||
|
||||
.icon-github1:before {
|
||||
content: "\e977";
|
||||
}
|
||||
|
||||
.icon-gitlab:before {
|
||||
content: "\e973";
|
||||
}
|
||||
|
||||
.icon-a-lianhe6:before {
|
||||
content: "\e972";
|
||||
}
|
||||
|
||||
.icon-a-22ziliaoshouce-xianxing:before {
|
||||
content: "\e971";
|
||||
}
|
||||
|
||||
.icon-changjiantou:before {
|
||||
content: "\e970";
|
||||
}
|
||||
|
||||
.icon-bangzhuzhongxinicon2:before {
|
||||
content: "\e96f";
|
||||
}
|
||||
|
||||
.icon-liulan1:before {
|
||||
content: "\e96e";
|
||||
}
|
||||
|
||||
.icon-a-zu2044:before {
|
||||
content: "\e96d";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,97 @@
|
|||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "41876673",
|
||||
"name": "贡献确权",
|
||||
"font_class": "gongxianquequan",
|
||||
"unicode": "e979",
|
||||
"unicode_decimal": 59769
|
||||
},
|
||||
{
|
||||
"icon_id": "657556",
|
||||
"name": "分期-选中",
|
||||
"font_class": "xuanzhong5",
|
||||
"unicode": "e97a",
|
||||
"unicode_decimal": 59770
|
||||
},
|
||||
{
|
||||
"icon_id": "157771",
|
||||
"name": "细圆",
|
||||
"font_class": "big-circle",
|
||||
"unicode": "e978",
|
||||
"unicode_decimal": 59768
|
||||
},
|
||||
{
|
||||
"icon_id": "41539674",
|
||||
"name": "gitee",
|
||||
"font_class": "gitee",
|
||||
"unicode": "e974",
|
||||
"unicode_decimal": 59764
|
||||
},
|
||||
{
|
||||
"icon_id": "41539676",
|
||||
"name": "gitea",
|
||||
"font_class": "gitea",
|
||||
"unicode": "e975",
|
||||
"unicode_decimal": 59765
|
||||
},
|
||||
{
|
||||
"icon_id": "41539677",
|
||||
"name": "coding",
|
||||
"font_class": "coding",
|
||||
"unicode": "e976",
|
||||
"unicode_decimal": 59766
|
||||
},
|
||||
{
|
||||
"icon_id": "41539675",
|
||||
"name": "github",
|
||||
"font_class": "github1",
|
||||
"unicode": "e977",
|
||||
"unicode_decimal": 59767
|
||||
},
|
||||
{
|
||||
"icon_id": "41539679",
|
||||
"name": "gitlab",
|
||||
"font_class": "gitlab",
|
||||
"unicode": "e973",
|
||||
"unicode_decimal": 59763
|
||||
},
|
||||
{
|
||||
"icon_id": "41195024",
|
||||
"name": "联合 6",
|
||||
"font_class": "a-lianhe6",
|
||||
"unicode": "e972",
|
||||
"unicode_decimal": 59762
|
||||
},
|
||||
{
|
||||
"icon_id": "40333433",
|
||||
"name": "使用手册",
|
||||
"font_class": "a-22ziliaoshouce-xianxing",
|
||||
"unicode": "e971",
|
||||
"unicode_decimal": 59761
|
||||
},
|
||||
{
|
||||
"icon_id": "40172194",
|
||||
"name": "长箭头",
|
||||
"font_class": "changjiantou",
|
||||
"unicode": "e970",
|
||||
"unicode_decimal": 59760
|
||||
},
|
||||
{
|
||||
"icon_id": "37836900",
|
||||
"name": "帮助中心icon",
|
||||
"font_class": "bangzhuzhongxinicon2",
|
||||
"unicode": "e96f",
|
||||
"unicode_decimal": 59759
|
||||
},
|
||||
{
|
||||
"icon_id": "36898536",
|
||||
"name": "浏览",
|
||||
"font_class": "liulan1",
|
||||
"unicode": "e96e",
|
||||
"unicode_decimal": 59758
|
||||
},
|
||||
{
|
||||
"icon_id": "36020261",
|
||||
"name": "组 2044",
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@
|
|||
<meta name="theme-color" content="#000000">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="referrer" content="always">
|
||||
<meta name="google-site-verification" content="rGWc47_e6dmJlLtT6ngl3WSiXMsY8FCcll2dbdlNHm0" />
|
||||
<!-- 按需引用viewport content -->
|
||||
<meta name="viewport" content="">
|
||||
<link rel="canonical" href="https://gitlink.org.cn" data-turbo-transient="">
|
||||
<link rel="fluid-icon" href="https://www.gitlink.org.cn/images/logo.png" title="GitLink">
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
|
|
@ -51,7 +54,6 @@
|
|||
<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://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
|
||||
<meta name="viewport" content="">
|
||||
<%= htmlWebpackPlugin.tags.bodyTags %>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
|
|
|
|||
|
|
@ -1418,28 +1418,6 @@
|
|||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* 解析TeX(KaTeX)科学公式
|
||||
* TeX(KaTeX) Renderer
|
||||
*
|
||||
* @returns {editormd} 返回editormd的实例对象
|
||||
*/
|
||||
|
||||
katexRender: function () {
|
||||
|
||||
if (timer === null) {
|
||||
return this;
|
||||
}
|
||||
this.previewContainer.find("." + editormd.classNames.tex).each(function () {
|
||||
var tex = $(this);
|
||||
editormd.$katex.render(tex.text(), tex[0]);
|
||||
|
||||
tex.find(".katex").css("font-size", "1.6em");
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* 解析和渲染流程图及时序图
|
||||
* FlowChart and SequenceDiagram Renderer
|
||||
|
|
@ -1882,6 +1860,63 @@
|
|||
}
|
||||
|
||||
var marked = editormd.$marked;
|
||||
const kateX = {
|
||||
name: 'kateX',
|
||||
level: 'block', // Is this a block-level or inline-level tokenizer?
|
||||
start(src) {
|
||||
// 匹配以 $$ 开头和结尾的 KaTeX 表达式
|
||||
const startRegex = /^\$\$[^$]+?\$\$(?:\n|$)/;
|
||||
|
||||
// 匹配以 $ 开头和结尾的 KaTeX 表达式
|
||||
const inlineRegex = /^\$[^$]+?\$(?:\n|$)/;
|
||||
|
||||
// 检查是否有块级 KaTeX 表达式
|
||||
const blockMatch = src.match(startRegex);
|
||||
if (blockMatch) {
|
||||
return blockMatch.index;
|
||||
}
|
||||
|
||||
// 检查是否有行内 KaTeX 表达式
|
||||
const inlineMatch = src.match(inlineRegex);
|
||||
if (inlineMatch) {
|
||||
return inlineMatch.index;
|
||||
}
|
||||
|
||||
// 如果没有匹配的内容,则返回 null 或 undefined
|
||||
return null;
|
||||
},
|
||||
tokenizer(src, tokens) {
|
||||
const match = src.match(/^\$([^\$]+)\$/);
|
||||
if (match) {
|
||||
return {
|
||||
type: 'kateX',
|
||||
raw: match[0],
|
||||
text: match[1].trim(),
|
||||
displayMode: false
|
||||
};
|
||||
}
|
||||
const matchDisplay = src.match(/^\$\$([^\$]+)\$\$/);
|
||||
if (matchDisplay) {
|
||||
return {
|
||||
type: 'kateX',
|
||||
raw: matchDisplay[0],
|
||||
text: matchDisplay[1].trim(),
|
||||
displayMode: true
|
||||
};
|
||||
}
|
||||
return false;
|
||||
},
|
||||
renderer(token) {
|
||||
let renderString = ''
|
||||
try {
|
||||
renderString = katex.renderToString(token.text, { displayMode: token.displayMode })
|
||||
} catch (error) {
|
||||
renderString = `<p style="color:#cc0000" title="${ error.message }">${ token.raw }`
|
||||
}
|
||||
return renderString
|
||||
}
|
||||
};
|
||||
|
||||
var markdownToC = this.markdownToC = [];
|
||||
var rendererOptions = this.markedRendererOptions = {
|
||||
toc: settings.toc,
|
||||
|
|
@ -1908,6 +1943,10 @@
|
|||
smartLists: true,
|
||||
smartypants: true
|
||||
};
|
||||
|
||||
if (editormd.kaTeXLoaded) {
|
||||
marked.use({ extensions: [kateX] });
|
||||
}
|
||||
|
||||
marked.setOptions(markedOptions);
|
||||
|
||||
|
|
@ -1958,12 +1997,12 @@
|
|||
editormd.loadKaTeX(function () {
|
||||
editormd.$katex = katex;
|
||||
editormd.kaTeXLoaded = true;
|
||||
_this.katexRender();
|
||||
marked.use({ extensions: [kateX] });
|
||||
_this.save();
|
||||
});
|
||||
}
|
||||
else {
|
||||
editormd.$katex = katex;
|
||||
this.katexRender();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3418,25 +3457,15 @@
|
|||
};
|
||||
|
||||
markedRenderer.paragraph = function (text) {
|
||||
var isTeXInline = /\$\$(.*)\$\$/g.test(text);
|
||||
var isTeXLine = /^\$\$(.*)\$\$$/.test(text);
|
||||
var isTeXAddClass = (isTeXLine) ? " class=\"" + editormd.classNames.tex + "\"" : "";
|
||||
|
||||
var isToC = (settings.tocm) ? /^(\[TOC\]|\[TOCM\])$/.test(text) : /^\[TOC\]$/.test(text);
|
||||
var isToCMenu = /^\[TOCM\]$/.test(text);
|
||||
|
||||
if (!isTeXLine && isTeXInline) {
|
||||
text = text.replace(/(\$\$([^\$]*)\$\$)+/g, function ($1, $2) {
|
||||
return "<span class=\"" + editormd.classNames.tex + "\">" + $2.replace(/\$/g, "") + "</span>";
|
||||
});
|
||||
}
|
||||
else {
|
||||
text = (isTeXLine) ? text.replace(/\$/g, "") : text;
|
||||
}
|
||||
|
||||
var tocHTML = "<div class=\"markdown-toc editormd-markdown-toc\">" + text + "</div>";
|
||||
|
||||
return (isToC) ? ((isToCMenu) ? "<div class=\"editormd-toc-menu\">" + tocHTML + "</div><br/>" : tocHTML)
|
||||
: ((pageBreakReg.test(text)) ? this.pageBreak(text) : "<p" + isTeXAddClass + ">" + this.atLink(this.emoji(text)) + "</p>\n");
|
||||
: ((pageBreakReg.test(text)) ? this.pageBreak(text) : this.atLink(this.emoji(text)) + "</p>\n");
|
||||
};
|
||||
|
||||
markedRenderer.code = function (code, lang, escaped) {
|
||||
|
|
@ -3803,26 +3832,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (settings.tex) {
|
||||
var katexHandle = function () {
|
||||
div.find("." + editormd.classNames.tex).each(function () {
|
||||
var tex = $(this);
|
||||
katex.render(tex.text(), tex[0]);
|
||||
tex.find(".katex").css("font-size", "1.6em");
|
||||
});
|
||||
};
|
||||
|
||||
if (settings.autoLoadKaTeX && !editormd.$katex && !editormd.kaTeXLoaded) {
|
||||
this.loadKaTeX(function () {
|
||||
editormd.$katex = katex;
|
||||
editormd.kaTeXLoaded = true;
|
||||
katexHandle();
|
||||
});
|
||||
}
|
||||
else {
|
||||
katexHandle();
|
||||
}
|
||||
}
|
||||
|
||||
div.getMarkdown = function () {
|
||||
return saveTo.val();
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ app.use('/build', express.static('build'));
|
|||
const options = (target) => {
|
||||
return {
|
||||
target: target,
|
||||
changeOrigin: false, // 允许在请求头中更改主机
|
||||
changeOrigin: process.env.NODE_ENV === 'dev' ? true : false, // 服务器不允许在请求头中更改主机
|
||||
timeout: 30000,
|
||||
secure: process.env.NODE_ENV === 'dev' ? false : true, // 忽略证书验证
|
||||
onProxyRes: (proxyRes, req, res) => {
|
||||
// 代理成功后输出日志
|
||||
Logger.info(`Proxy to ${req.url} responded with status ${proxyRes.statusCode}`);
|
||||
|
|
@ -29,25 +30,27 @@ const options = (target) => {
|
|||
};
|
||||
}
|
||||
|
||||
const proxy = createProxyMiddleware(options(`http://localhost:${ rubyPort }`));
|
||||
// const proxy = createProxyMiddleware(options(url));
|
||||
let proxy
|
||||
|
||||
if (process.env.NODE_ENV === 'dev') {
|
||||
// 本地调试用设置代理
|
||||
proxy = createProxyMiddleware(options(url));
|
||||
app.use(['/api/zone', '/api/cms'], (req, res) => {
|
||||
const proxy = createProxyMiddleware(options(zoneUrl));
|
||||
proxy(req, res);
|
||||
});
|
||||
app.use(['/api', '/images', '/system', '/favicon', '/robots.txt', '/sitemap*.xml', '/sitemap*.txt', '/favicon.ico', '/admins', '/assets', '/attachments', '/oauth', '/settings'], (req, res) => {
|
||||
proxy(req, res);
|
||||
});
|
||||
} else {
|
||||
proxy = createProxyMiddleware(options(`http://localhost:${ rubyPort }`));
|
||||
// 设置代理
|
||||
app.use(['/api', '/admins', '/attachments', '/oauth', '/competitions', '/projects', '/auth', '/settings'], (req, res) => {
|
||||
proxy(req, res);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 本地调试用设置代理
|
||||
// app.use(['/api/zone', '/api/cms'], (req, res) => {
|
||||
// const proxy = createProxyMiddleware(options(zoneUrl));
|
||||
// proxy(req, res);
|
||||
// });
|
||||
|
||||
// 本地调试用设置代理
|
||||
// app.use(['/api', '/images', '/system', '/favicon', '/robots.txt', '/sitemap*.xml', '/sitemap*.txt', '/favicon.ico', '/admins', '/assets', '/attachments', '/oauth'], (req, res) => {
|
||||
// proxy(req, res);
|
||||
// });
|
||||
|
||||
// 设置代理
|
||||
app.use(['/api', '/admins', '/attachments', '/oauth', '/competitions'], (req, res) => {
|
||||
proxy(req, res);
|
||||
});
|
||||
|
||||
// 匹配路径,匹配到的返回处理后的html,没匹配到转发到后端
|
||||
app.get('*',async function (req,res) {
|
||||
|
|
|
|||
142
server/render.js
|
|
@ -1,28 +1,30 @@
|
|||
// import React from "react";
|
||||
// import {renderToString} from "react-dom/server";
|
||||
import React from "react";
|
||||
import {renderToString} from "react-dom/server";
|
||||
import {StaticRouter, matchPath} from "react-router-dom";
|
||||
// import {renderRoutes} from "react-router-config";
|
||||
|
||||
import StyleContext from 'isomorphic-style-loader/StyleContext'
|
||||
import {renderRoutes} from "react-router-config";
|
||||
import Routes, { deepRoutes, specialRoute } from "../Routes";
|
||||
// import { Provider } from "react-redux";
|
||||
// import { serverStore } from "../src/redux/stores/configureStore";
|
||||
// import App from "../src/App";
|
||||
// import { Route } from 'react-router-dom';
|
||||
// import { setDefaultMeta } from '../src/common/UrlTool'
|
||||
import { Provider } from "react-redux";
|
||||
import { serverStore } from "../src/redux/stores/configureStore";
|
||||
import { setDefaultMeta } from '../src/common/UrlTool'
|
||||
import Logger from "./log";
|
||||
import { changeHead } from './setHead'
|
||||
|
||||
// 目前只用项目详情页的,不需要动态添加
|
||||
const css = new Set() // 这个必须在路由函数里面,在外面的话,就会累加出现之前的css
|
||||
const insertCss = (...styles) => styles.forEach(style => css.add(style._getCss()));
|
||||
|
||||
export const render = async (req,res)=>{
|
||||
let _route = null,
|
||||
_match = null;
|
||||
// Logger.info(`${req.url} UA:${req.headers['user-agent']}`)
|
||||
Logger.info(`${req.url} UA:${req.headers['user-agent']}`)
|
||||
|
||||
// let store = serverStore();
|
||||
let store = serverStore();
|
||||
|
||||
function matchSubRoutes(routes, url) {
|
||||
for (const route of routes) {
|
||||
// 检查当前路由是否匹配
|
||||
let match = matchPath(url, route.path);
|
||||
let match = matchPath(url, { path: route.path, exact: true });
|
||||
if (match) {
|
||||
// 如果当前路由匹配,并且它有子路由,递归检查子路由
|
||||
if (route.routes) {
|
||||
|
|
@ -50,59 +52,87 @@ export const render = async (req,res)=>{
|
|||
code: 200,
|
||||
};
|
||||
|
||||
|
||||
if (_route && _route.component && _route.component.preFetch) {
|
||||
|
||||
// 设置服务端请求cookie
|
||||
if (req.headers.cookie) {
|
||||
let cookies = req.headers.cookie.split(';')
|
||||
for (let index = 0; index < cookies.length; index++) {
|
||||
const element = cookies[index];
|
||||
domObj.window.document.cookie = element
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
context = await _route.component.preFetch({
|
||||
store,
|
||||
match: _match,
|
||||
query: req.path,
|
||||
});
|
||||
|
||||
// 当前只做了项目详情页,没获取到数据使用原来的
|
||||
if(!store.getState().projectReducer.projectBase.id) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
let content = ''
|
||||
|
||||
// 匹配路由、并且不是特定一级路由、且不是只动态修改head的,在服务端渲染页面
|
||||
if (_route && !specialRoute.includes(_match.url && _match.url.replace('/', '')) && !_route.onlyHead) {
|
||||
content = renderToString((
|
||||
<Provider store={store}>
|
||||
<StaticRouter location={req.path} context={context}>
|
||||
<StyleContext.Provider value={{insertCss}}>
|
||||
{renderRoutes(Routes)}
|
||||
{/* <Route path='/:owner/:projectsId' exact component={App}></Route> */}
|
||||
</StyleContext.Provider>
|
||||
</StaticRouter>
|
||||
</Provider>
|
||||
))
|
||||
}
|
||||
|
||||
if (!content) {
|
||||
// 未匹配到详情页恢复默认header
|
||||
setDefaultMeta()
|
||||
} else {
|
||||
// 匹配到服务端渲染页面注入state
|
||||
let script = domObj.window.document.getElementById('initState')
|
||||
if (!script) {
|
||||
script = domObj.window.document.createElement('script')
|
||||
script.setAttribute('id', 'initState')
|
||||
}
|
||||
script.textContent = `window.__initState__ = ${ JSON.stringify(store.getState()) }`
|
||||
|
||||
// 目前直接把详情页涉及到的css抽出来塞到返回的html里,没有使用insertCss
|
||||
const styleNode = domObj.window.document.createElement('style')
|
||||
styleNode.type = 'text/css'
|
||||
// styleNode.innerHTML = `${ [...css].join('') }`
|
||||
styleNode.innerHTML = detailCss
|
||||
domObj.window.document.head.appendChild(script);
|
||||
domObj.window.document.head.appendChild(styleNode);
|
||||
}
|
||||
|
||||
if (_route && !specialRoute.includes(_match.url && _match.url.replace('/', ''))) {
|
||||
Logger.info(`matchRoot: ${ _match.url }`)
|
||||
await changeHead(_route, _match.params)
|
||||
// 匹配上的,并且只修改head的页面
|
||||
if (_route.onlyHead) {
|
||||
Logger.info(`matchRoot: ${ _match.url }`)
|
||||
const result = await changeHead(_route, _match.params)
|
||||
if (!result) return result
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// if (_route && _route.component && _route.component.preFetch) {
|
||||
// context = await _route.component.preFetch({
|
||||
// store,
|
||||
// match: _match,
|
||||
// query: req.path,
|
||||
// });
|
||||
// }
|
||||
|
||||
// 暂时不开放ssr,只修改head
|
||||
// const content = renderToString((
|
||||
// <Provider store={store}>
|
||||
// <StaticRouter location={req.path} context={context}>
|
||||
// {renderRoutes(Routes)}
|
||||
// {/* <Route path='/:owner/:projectsId' exact component={App}></Route> */}
|
||||
// </StaticRouter>
|
||||
// </Provider>
|
||||
// ))
|
||||
|
||||
// 暂时不开放ssr,只修改head
|
||||
// if (!content) {
|
||||
// // 未匹配到详情页恢复默认header
|
||||
// setDefaultMeta()
|
||||
// } else {
|
||||
// // 匹配到服务端渲染页面注入state
|
||||
// let script = domObj.window.document.getElementById('initState')
|
||||
// if (!script) {
|
||||
// script = domObj.window.document.createElement('script')
|
||||
// script.setAttribute('id', 'initState')
|
||||
// }
|
||||
// script.textContent = `window.__initState__ = ${ JSON.stringify(store.getState()) }`
|
||||
|
||||
// domObj.window.document.head.appendChild(script);
|
||||
// }
|
||||
|
||||
|
||||
let html = domObj.serialize()
|
||||
|
||||
const prepHTML=(data,rootString)=>{
|
||||
// 暂时不开放ssr,只修改head
|
||||
// data=data.replace('<div id="root" class="page -layout-v -fit widthunit"></div>',`<div id="root" class="page -layout-v -fit widthunit">${rootString}</div>`);
|
||||
data=data.replace('<div id="root" class="page -layout-v -fit widthunit"></div>',`<div id="root" class="page -layout-v -fit widthunit">${rootString}</div>`);
|
||||
return data;
|
||||
}
|
||||
// 暂时不开放ssr,只修改head
|
||||
// res.send(prepHTML(html, content))
|
||||
res.send(prepHTML(html, ''))
|
||||
|
||||
res.send(prepHTML(html, content))
|
||||
|
||||
// store = null
|
||||
store = null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,20 +6,23 @@ export const changeHead = async ({ key }, params) => {
|
|||
let res
|
||||
let data
|
||||
switch (key) {
|
||||
case 'detail':
|
||||
res = await getProjectDetailFunc(params.owner, params.projectsId);
|
||||
data = res.data
|
||||
if (data && data.status === 1) {
|
||||
let keyWords=`${params.owner},${params.projectsId}${ data.topics.length > 0 && ','}${ data.topics.length > 0 && data.topics.map(item => item.name).join(',') }`;
|
||||
let title= `${params.owner}/${params.projectsId}${data.description?':'+data.description:''}`;
|
||||
setSeoMeta(keyWords,title,data.description || '',`/${params.owner}/${params.projectsId}`,params.owner,params.projectsId);
|
||||
}
|
||||
break;
|
||||
// 详情页不再修改head,直接ssr渲染页面
|
||||
// case 'detail':
|
||||
// res = await getProjectDetailFunc(params.owner, params.projectsId);
|
||||
// data = res.data
|
||||
// if (data && data.status === 1) {
|
||||
// let keyWords=`${params.owner},${params.projectsId}${ data.topics.length > 0 && ','}${ data.topics.length > 0 && data.topics.map(item => item.name).join(',') }`;
|
||||
// let title= `${params.owner}/${params.projectsId}${data.description?':'+data.description:''}`;
|
||||
// setSeoMeta(keyWords,title,data.description || '',`/${params.owner}/${params.projectsId}`,params.owner,params.projectsId);
|
||||
// }
|
||||
// break;
|
||||
case 'zoneNews':
|
||||
res = await getNewsDetail(params.id)
|
||||
data = res.data.data
|
||||
if (data) {
|
||||
setSeoMeta(`${data.name}`, data.name, data.summary || '', `/zone/${params.deptId}/newdetail/${ params.id }`)
|
||||
setSeoMeta(`${data.keywords || data.name}`, data.name, data.summary || '', `/zone/${params.deptId}/newdetail/${ params.id }`)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
break;
|
||||
case 'zone':
|
||||
|
|
@ -27,17 +30,22 @@ export const changeHead = async ({ key }, params) => {
|
|||
data = res.data.data
|
||||
if (data) {
|
||||
setSeoMeta(`${data.name}`, data.name, data.subTitle || '', `/zone/${params.deptId}`)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
break;
|
||||
case 'owner':
|
||||
res = await getOwnerInfo(params.owner);
|
||||
data = res.data
|
||||
const name = data.nickname || data.username
|
||||
if (data && data.status === 1) {
|
||||
if (data && data.name) {
|
||||
setSeoMeta(`${name}`, name, data.description || '', `/${params.owner}`)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
const jsdom = require("jsdom");
|
||||
import fs from 'fs'
|
||||
import path from 'path';
|
||||
import axios from "axios";
|
||||
|
||||
import { getSetting } from '../src/services/project'
|
||||
const { JSDOM } = jsdom;
|
||||
|
||||
const html = fs.readFileSync(path.join(path.resolve('./build'),'index.html'),'utf-8');
|
||||
// 压缩的项目详情页需要的css
|
||||
const css = fs.readFileSync(path.join(path.resolve('./build/css'),'detail.css'),'utf-8');
|
||||
const { window } = new JSDOM(html);
|
||||
|
||||
const $ = require( "jquery" )( window )
|
||||
|
|
@ -13,20 +14,20 @@ const $ = require( "jquery" )( window )
|
|||
global.window = window;
|
||||
global.document = window.document;
|
||||
global.navigator = window.navigator;
|
||||
global.localStorage = {}
|
||||
global.localStorage = {};
|
||||
global.defaultSetting = {}
|
||||
// 全局缓存css
|
||||
global.detailCss = css
|
||||
|
||||
const setGlobalSetting = async () => {
|
||||
const setting = await getSetting()
|
||||
if (setting.data) {
|
||||
global.defaultSetting = setting.data.setting
|
||||
}
|
||||
}
|
||||
|
||||
setGlobalSetting()
|
||||
|
||||
export const getDomObj = () => {
|
||||
return new JSDOM(html)
|
||||
}
|
||||
|
||||
// axios.get('https://gw.alipayobjects.com/os/lib/alipay/alex/2.0.19/bundle/alex.all.global.min.js')
|
||||
// .then(response => {
|
||||
// // 处理响应
|
||||
// if (response) {
|
||||
// // 这里你可以直接使用response.data,而不是eval
|
||||
// eval(response);
|
||||
// }
|
||||
// })
|
||||
// .catch(error => {
|
||||
// console.error('Error fetching data:', error);
|
||||
// });
|
||||
|
|
|
|||
78
src/App.js
|
|
@ -23,6 +23,9 @@ import SiderBarHelp from './glcc/siderBarHelp';
|
|||
import { SnackbarHOC, configShareForCustom } from 'educoder';
|
||||
import { initAxiosInterceptors } from './AppConfig'
|
||||
import cookie from 'react-cookies';
|
||||
import InfosIndex from './forge/users/Index'
|
||||
import OrganizeIndex from './forge/Team/Index'
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
window.marked = marked;
|
||||
const theme = createMuiTheme({
|
||||
|
|
@ -74,15 +77,15 @@ const http500 = Loadable({
|
|||
loader: () => import('./modules/500/http500'),
|
||||
loading: Loading,
|
||||
})
|
||||
const InfosIndex = Loadable({
|
||||
loader: () => import('./forge/users/Index'),
|
||||
loading: Loading,
|
||||
})
|
||||
// const InfosIndex = Loadable({
|
||||
// loader: () => import('./forge/users/Index'),
|
||||
// loading: Loading,
|
||||
// })
|
||||
// 组织
|
||||
const OrganizeIndex = Loadable({
|
||||
loader: () => import('./forge/Team/Index'),
|
||||
loading: Loading,
|
||||
})
|
||||
// const OrganizeIndex = Loadable({
|
||||
// loader: () => import('./forge/Team/Index'),
|
||||
// loading: Loading,
|
||||
// })
|
||||
|
||||
const Search = Loadable({
|
||||
loader: () => import('./modules/search/'),
|
||||
|
|
@ -90,7 +93,7 @@ const Search = Loadable({
|
|||
})
|
||||
|
||||
const WikiPreview = Loadable({
|
||||
loader: () => import('./forge/Wiki/Preview'),
|
||||
loader: () => import('./forge/Wiki/page/preview'),
|
||||
loading: Loading,
|
||||
})
|
||||
|
||||
|
|
@ -156,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) {
|
||||
|
|
@ -168,7 +176,7 @@ class App extends Component {
|
|||
mydisplay: false,
|
||||
occupation: 0,
|
||||
mygetHelmetapi: null,
|
||||
pathType: null,
|
||||
pathType: props.projectBase && props.projectBase.author && props.projectBase.author.type,
|
||||
pathName: null,
|
||||
}
|
||||
}
|
||||
|
|
@ -332,11 +340,20 @@ 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/>} */}
|
||||
{pathName && pathName.toLowerCase() === 'glcc' && <SiderBarHelp/>}
|
||||
{/* <Router> */}
|
||||
<Switch>
|
||||
{
|
||||
pathType ?
|
||||
<Switch>
|
||||
{/* iframe页面 */}
|
||||
<Route path="/hiagent"
|
||||
render={
|
||||
(props) => (<Iframe {...this.props} {...props} {...this.state} />)
|
||||
}
|
||||
></Route>
|
||||
{/* wiki预览 */}
|
||||
<Route path="/:owner/:projectsId/wiki/preview/:projectName/:projectId" render={
|
||||
<Route path="/:owner/:proIdentity/:projectId/wiki/preview" render={
|
||||
(props) => {
|
||||
return (<WikiPreview {...this.props} {...props} {...this.state} />)
|
||||
}
|
||||
|
|
@ -514,14 +531,6 @@ class App extends Component {
|
|||
</Route> : pathType === '404' ? <Route component={Shixunnopage} />:
|
||||
""
|
||||
}
|
||||
<Route exact path="/"
|
||||
render={
|
||||
(props) => (
|
||||
<Home {...props} {...this.props} {...this.state}/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
{/* 个人主页 */}
|
||||
<Route path="/:username"
|
||||
render={
|
||||
|
|
@ -533,6 +542,16 @@ class App extends Component {
|
|||
|
||||
<Route component={Shixunnopage} />
|
||||
</Switch>
|
||||
:
|
||||
<Route exact path="/"
|
||||
render={
|
||||
(props) => (
|
||||
<Home {...props} {...this.props} {...this.state}/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
}
|
||||
|
||||
</MuiThemeProvider>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
|
@ -650,5 +669,18 @@ moment.defineLocale('zh-cn', {
|
|||
doy: 4 // The week that contains Jan 4th is the first week of the year.
|
||||
}
|
||||
});
|
||||
export default SnackbarHOC()(App);
|
||||
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const {
|
||||
projectBase,
|
||||
} = state.projectReducer;
|
||||
return {
|
||||
projectBase,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
)(SnackbarHOC()(App));
|
||||
|
||||
|
|
|
|||
|
|
@ -32,8 +32,9 @@ export function initAxiosInterceptors(props) {
|
|||
// 判断网络是否连接
|
||||
initOnlineOfflineListener();
|
||||
|
||||
|
||||
var proxy = "https://testforgeplus.trustie.net";
|
||||
// var proxy = "http://172.20.32.201:4000";
|
||||
// var proxy = "https://www.gitlink.org.cn";
|
||||
|
||||
//响应前的设置
|
||||
axios.interceptors.request.use(
|
||||
|
|
@ -101,7 +102,7 @@ export function initAxiosInterceptors(props) {
|
|||
// 邀请页面不进行404跳转
|
||||
if( window.location.pathname.includes('/invite') && (responseURL.includes('/simple.json')||responseURL.includes('/detail.json')||responseURL.includes('/menu_list.json'))){
|
||||
}else{
|
||||
// locationurl('/nopage');
|
||||
locationurl('/nopage');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import React from "react";
|
||||
import md5 from 'md5';
|
||||
import {Input} from "antd";
|
||||
const { Search } = Input;
|
||||
import { url as ssrOrigin, host as ssrHost } from '../ssrUrl'
|
||||
|
||||
const { Search } = Input;
|
||||
|
||||
if (!__SERVER__) {
|
||||
const $ = window.$;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
import './index.scss';
|
||||
import React, { useState } from 'react';
|
||||
import { Form, Button, Input } from 'antd';
|
||||
import QuillForEditor from '../../quillForEditor';
|
||||
// import QuillForEditor from '../../quillForEditor';
|
||||
const FormItem = Form.Item;
|
||||
|
||||
function CommentForm(props) {
|
||||
|
|
@ -116,7 +116,7 @@ function CommentForm(props) {
|
|||
)
|
||||
}
|
||||
|
||||
<QuillForEditor
|
||||
{/* <QuillForEditor
|
||||
imgAttrs={{ width: '60px', height: '30px' }}
|
||||
wrapStyle={{
|
||||
height: showQuill ? 'auto' : '0px',
|
||||
|
|
@ -131,7 +131,7 @@ function CommentForm(props) {
|
|||
value={ctx}
|
||||
showUploadImage={handleShowImage}
|
||||
onContentChange={handleContentChange}
|
||||
/>
|
||||
/> */}
|
||||
</FormItem>
|
||||
<FormItem style={{ textAlign: 'right', display: showQuill ? 'block' : 'none' }}>
|
||||
<Button onClick={handleCancle}>取消</Button>
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export { default as ActionBtn } from './course/ActionBtn'
|
|||
|
||||
export { default as MarkdownToHtml } from './components/markdown/MarkdownToHtml'
|
||||
|
||||
export { default as QuillForEditor } from './quillForEditor'
|
||||
// export { default as QuillForEditor } from './quillForEditor'
|
||||
|
||||
export { default as Clappr } from './components/media/Clappr'
|
||||
export { default as AliyunUploader } from './components/media/AliyunUploader'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import marked from 'marked'
|
||||
import { escape } from 'marked/src/helpers'
|
||||
import { renderToString } from 'katex'
|
||||
|
||||
function indentCodeCompensation(raw, text) {
|
||||
const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
|
||||
|
|
@ -91,7 +92,7 @@ const tokenizer = {
|
|||
text
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const latexRegex = /(?:\${2})([^\n`]+?)(?:\${2})/gi
|
||||
|
|
@ -119,20 +120,20 @@ function replace_math_with_ids(text) {
|
|||
}
|
||||
|
||||
|
||||
const original_listitem = renderer.listitem
|
||||
renderer.listitem = function (text, task, checked) {
|
||||
return original_listitem(replace_math_with_ids(text), task, checked)
|
||||
}
|
||||
// const original_listitem = renderer.listitem
|
||||
// renderer.listitem = function (text, task, checked) {
|
||||
// return original_listitem(replace_math_with_ids(text), task, checked)
|
||||
// }
|
||||
|
||||
const original_paragraph = renderer.paragraph
|
||||
renderer.paragraph = function (text) {
|
||||
return original_paragraph(replace_math_with_ids(text))
|
||||
}
|
||||
// const original_paragraph = renderer.paragraph
|
||||
// renderer.paragraph = function (text) {
|
||||
// return original_paragraph(replace_math_with_ids(text))
|
||||
// }
|
||||
|
||||
const original_tablecell = renderer.tablecell
|
||||
renderer.tablecell = function (content, flags) {
|
||||
return original_tablecell(replace_math_with_ids(content), flags)
|
||||
}
|
||||
// const original_tablecell = renderer.tablecell
|
||||
// renderer.tablecell = function (content, flags) {
|
||||
// return original_tablecell(replace_math_with_ids(content), flags)
|
||||
// }
|
||||
|
||||
renderer.code = function (code, infostring, escaped) {
|
||||
const lang = (infostring || '').match(/\S*/)[0];
|
||||
|
|
@ -150,6 +151,16 @@ renderer.code = function (code, infostring, escaped) {
|
|||
|
||||
}
|
||||
|
||||
function cleanString(str) {
|
||||
// 移除整个HTML标签及其内容
|
||||
let cleanedStr = str.replace(/<[^>]*>[^<]*<\/[^>]*>/g, '');
|
||||
// 移除剩余的HTML标签
|
||||
cleanedStr = cleanedStr.replace(/<[^>]*>/g, '');
|
||||
// 移除特殊字符
|
||||
cleanedStr = cleanedStr.replace(/[.,/#!$%^&*;:{}=\-_`~():,。¥;「」|?》《~·【】‘、!]/g, '');
|
||||
return cleanedStr;
|
||||
}
|
||||
|
||||
renderer.heading = function (text, level, raw) {
|
||||
let anchor = this.options.headerPrefix + raw.toLowerCase().replace(/[^\w\\u4e00-\\u9fa5]]+/g, '-');
|
||||
toc.push({
|
||||
|
|
@ -157,9 +168,10 @@ renderer.heading = function (text, level, raw) {
|
|||
level: level,
|
||||
text: text
|
||||
})
|
||||
let id = anchor.replace(/[.,/#!$%^&*;:{}=\-_`~():,。¥;「」|?》《~·【】‘、!]/g,"");
|
||||
let id = cleanString(anchor);
|
||||
return '<h' + level + ' id="' + id + '" class="markdown_anchors"><a name="#'+id+'" class="anchors"><i class="iconfont icon-lianjieicon font-14"></i></a>' + text + '</h' + level + '>'
|
||||
}
|
||||
|
||||
marked.setOptions({
|
||||
silent: true,
|
||||
smartypants: true,
|
||||
|
|
@ -167,6 +179,66 @@ marked.setOptions({
|
|||
pedantic: false
|
||||
})
|
||||
|
||||
const kateX = {
|
||||
name: 'kateX',
|
||||
level: 'block', // Is this a block-level or inline-level tokenizer?
|
||||
start(src) {
|
||||
// 匹配以 $$ 开头和结尾的 KaTeX 表达式
|
||||
const startRegex = /^\$\$[^$]+?\$\$(?:\n|$)/;
|
||||
|
||||
// 匹配以 $ 开头和结尾的 KaTeX 表达式
|
||||
const inlineRegex = /^\$[^$]+?\$(?:\n|$)/;
|
||||
|
||||
// 检查是否有块级 KaTeX 表达式
|
||||
const blockMatch = src.match(startRegex);
|
||||
if (blockMatch) {
|
||||
return blockMatch.index;
|
||||
}
|
||||
|
||||
// 检查是否有行内 KaTeX 表达式
|
||||
const inlineMatch = src.match(inlineRegex);
|
||||
if (inlineMatch) {
|
||||
return inlineMatch.index;
|
||||
}
|
||||
|
||||
// 如果没有匹配的内容,则返回 null 或 undefined
|
||||
return null;
|
||||
},
|
||||
tokenizer(src, tokens) {
|
||||
const match = src.match(/^\$([^\$]+)\$/);
|
||||
if (match) {
|
||||
return {
|
||||
type: 'kateX',
|
||||
raw: match[0],
|
||||
text: match[1].trim(),
|
||||
displayMode: false
|
||||
};
|
||||
}
|
||||
const matchDisplay = src.match(/^\$\$([^\$]+)\$\$/);
|
||||
if (matchDisplay) {
|
||||
return {
|
||||
type: 'kateX',
|
||||
raw: matchDisplay[0],
|
||||
text: matchDisplay[1].trim(),
|
||||
displayMode: true
|
||||
};
|
||||
}
|
||||
return false;
|
||||
},
|
||||
renderer(token) {
|
||||
let renderString = ''
|
||||
try {
|
||||
renderString = renderToString(token.text, { displayMode: token.displayMode})
|
||||
} catch (error) {
|
||||
renderString = `<p style="color:#cc0000" title="${ error.message }">${ token.raw }`
|
||||
}
|
||||
return renderString
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
marked.use({ extensions: [kateX] });
|
||||
|
||||
marked.use({ tokenizer, renderer });
|
||||
|
||||
export default marked
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import './index.scss'
|
||||
import 'quill/dist/quill.core.css' // 核心样式
|
||||
import 'quill/dist/quill.snow.css' // 有工具栏
|
||||
import 'quill/dist/quill.bubble.css' // 无工具栏
|
||||
// import 'quill/dist/quill.core.css' // 核心样式
|
||||
// import 'quill/dist/quill.snow.css' // 有工具栏
|
||||
// import 'quill/dist/quill.bubble.css' // 无工具栏
|
||||
import './font.css'
|
||||
import React, { useState, useRef, useEffect } from 'react'
|
||||
import Quill from 'quill'
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ const host = window.location.protocol + '//' + window.location.host
|
|||
const wx = window.wx
|
||||
const appId = 'wxf8debe756b4a0309'
|
||||
|
||||
let settings = localStorage.chromesetting&&JSON.parse(localStorage.chromesetting);
|
||||
let settings = localStorage && localStorage.chromesetting && localStorage.chromesetting !== "undefined" && JSON.parse(localStorage.chromesetting);
|
||||
let actionUrl = settings && settings.common.zone +'/api';
|
||||
|
||||
const service = axios.create({
|
||||
|
|
@ -34,7 +34,6 @@ function requestForSignatrue (callback) {
|
|||
service.post(url, {
|
||||
url: currentUrl,
|
||||
}).then((response) => {
|
||||
console.log('got res')
|
||||
const data = response.data && response.data.data;
|
||||
|
||||
wx.config({
|
||||
|
|
@ -125,7 +124,6 @@ export function configShareForCourses () {
|
|||
|
||||
// detail
|
||||
export function configShareForCustom (title, desc, imgUrl, path) {
|
||||
console.log('--------------------', title,desc)
|
||||
requestForSignatrue(() => {
|
||||
console.log('configShareForCustom', host)
|
||||
const _url = window.location.href.split('#')[0];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect, useRef, useMemo , useState } from 'react'
|
||||
// import 'katex/dist/katex.min.css';
|
||||
import "../modules/courses/katex.css";
|
||||
import marked, { getTocContent, cleanToc, getMathExpressions, resetMathExpressions } from '../common/marked';
|
||||
import 'code-prettify';
|
||||
import dompurify from 'dompurify';
|
||||
|
|
@ -96,14 +96,13 @@ export default ({
|
|||
rs = rs.split(`<a href="`+`/${owner}/${projectsId}/issues/${item.project_issues_index}`+`">#${item.project_issues_index}</a>`).join(content);
|
||||
}
|
||||
}
|
||||
|
||||
rs = rs.replace(/(__special_katext_id_\d+__)/g, (_match, capture) => {
|
||||
const { type, expression } = math_expressions[capture];
|
||||
return renderToString(_unescape(expression) || '', { displayMode: type === 'block', throwOnError: false, output: 'html' })
|
||||
})
|
||||
rs = dompurify.sanitize(rs.replace(/▁/g, "▁▁▁"))
|
||||
rs = rs.split('<img ').join(`<img onerror="javascript:this.src='${ imgError }';"`) // 替换replaceall
|
||||
resetMathExpressions()
|
||||
// rs = rs.replace(/(__special_katext_id_\d+__)/g, (_match, capture) => {
|
||||
// const { type, expression } = math_expressions[capture];
|
||||
// return renderToString(_unescape(expression) || '', { displayMode: type === 'block', throwOnError: false, output: 'html' })
|
||||
// })
|
||||
// rs = dompurify.sanitize(rs.replace(/▁/g, "▁▁▁"))
|
||||
// rs = rs.split('<img ').join(`<img onerror="javascript:this.src='${ imgError }';"`) // 替换replaceall
|
||||
// resetMathExpressions()
|
||||
return rs
|
||||
}, [str,issues]);
|
||||
|
||||
|
|
|
|||
|
|
@ -123,24 +123,26 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.urlMenu{
|
||||
line-height: 30px;
|
||||
margin-bottom: 10px;
|
||||
padding:15px 20px 0px 20px;
|
||||
border-bottom: none;
|
||||
li.ant-menu-item{
|
||||
height: 30px;
|
||||
.downMenu {
|
||||
.urlMenu{
|
||||
line-height: 30px;
|
||||
padding:0px 5px;
|
||||
margin-right: 20px!important;
|
||||
&.ant-menu-item-selected,&.ant-menu-item-active{
|
||||
color: #333;
|
||||
}
|
||||
&.ant-menu-item-selected{
|
||||
border-color:#466aff!important;
|
||||
}
|
||||
&.ant-menu-item-active{
|
||||
border-color:transparent ;
|
||||
margin-bottom: 10px;
|
||||
padding:15px 20px 0px 20px;
|
||||
border-bottom: none;
|
||||
li.ant-menu-item{
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding:0px 5px;
|
||||
margin-right: 20px!important;
|
||||
&.ant-menu-item-selected,&.ant-menu-item-active{
|
||||
color: #333;
|
||||
}
|
||||
&.ant-menu-item-selected{
|
||||
border-color:#466aff!important;
|
||||
}
|
||||
&.ant-menu-item-active{
|
||||
border-color:transparent ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ li.ant-menu-item{
|
|||
z-index: 10000;
|
||||
}
|
||||
.laterest{
|
||||
background-color: #EF3131;
|
||||
background-color: #4baf50;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
|
|
@ -165,7 +165,7 @@ li.ant-menu-item{
|
|||
.hoverA{
|
||||
display:flex;
|
||||
align-items: center;
|
||||
max-width: 78px;
|
||||
max-width: 100px;
|
||||
&:hover a{
|
||||
color:#2A61FF !important ;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@
|
|||
}
|
||||
.sysnoticeBox{
|
||||
width: 100%;
|
||||
padding:80px 0px 34px;
|
||||
padding:80px 10px 34px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 780px;
|
||||
max-width: 800px;
|
||||
margin: 0px auto;
|
||||
p.ntitle{
|
||||
height: 33px;
|
||||
|
|
|
|||
|
|
@ -3,42 +3,43 @@ import { Modal , Button } from 'antd';
|
|||
import './Index.scss';
|
||||
import '../../css/index.scss';
|
||||
import RenderHtml from '../../../components/render-html';
|
||||
// import cookie from 'react-cookies';
|
||||
import axios from 'axios';
|
||||
import cookie from 'react-cookies';
|
||||
// import axios from 'axios';
|
||||
|
||||
function SystemNotice({showNotice,system_notification,history,login,hideSystemNotice}){
|
||||
function SystemNotice({system_notification,history}){
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
|
||||
useEffect(()=>{
|
||||
|
||||
if((system_notification && !system_notification.is_read) && showNotice && login){
|
||||
if(system_notification && !cookie.load('notice_stage')){
|
||||
setVisible(true);
|
||||
}
|
||||
},[system_notification,login])
|
||||
|
||||
function sureContinue() {
|
||||
if(login && ( system_notification && system_notification.id )){
|
||||
const url = `/users/${login}/system_notification_histories.json`;
|
||||
axios.post(url,{
|
||||
system_notification_id:system_notification.id
|
||||
}).then(result=>{
|
||||
setVisible(false);
|
||||
hideSystemNotice();
|
||||
}).catch(error=>{
|
||||
setVisible(false);
|
||||
hideSystemNotice();
|
||||
})
|
||||
}else{
|
||||
setVisible(false);
|
||||
hideSystemNotice();
|
||||
}
|
||||
// cookie.remove('notice_stage');
|
||||
},[system_notification])
|
||||
|
||||
// let inFifteenMinutes = new Date(new Date().getTime() + 24 * 3600 * 1000);//一天
|
||||
// // let inFifteenMinutes = new Date(new Date().getTime() + 60 * 1000);//一分钟
|
||||
// cookie.save('notice_stage', true,{ expires: inFifteenMinutes,path:"/" });
|
||||
function sureContinue() {
|
||||
// if(login && ( system_notification && system_notification.id )){
|
||||
// const url = `/users/${login}/system_notification_histories.json`;
|
||||
// axios.post(url,{
|
||||
// system_notification_id:system_notification.id
|
||||
// }).then(result=>{
|
||||
// setVisible(false);
|
||||
// hideSystemNotice();
|
||||
// }).catch(error=>{
|
||||
// setVisible(false);
|
||||
// hideSystemNotice();
|
||||
// })
|
||||
// }else{
|
||||
// setVisible(false);
|
||||
// hideSystemNotice();
|
||||
// }
|
||||
cookie.remove('notice_stage');
|
||||
|
||||
// setVisible(false);
|
||||
let inFifteenMinutes = new Date(new Date().getTime() + 24 * 3600 * 1000);//一天
|
||||
// let inFifteenMinutes = new Date(new Date().getTime() + 60 * 1000);//一分钟
|
||||
cookie.save('notice_stage', true,{ expires: inFifteenMinutes,path:"/" });
|
||||
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -50,6 +51,7 @@ function SystemNotice({showNotice,system_notification,history,login,hideSystemNo
|
|||
centered={true}
|
||||
closable={false}
|
||||
wrapClassName={'systemBox'}
|
||||
onCancel={()=>{sureContinue()}}
|
||||
>
|
||||
<div className="sysBox">
|
||||
<div className="sysnoticeBox">
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ function Releases({ owner, projectsId, releaseVersions, distribution }) {
|
|||
:
|
||||
<div className="mt8">
|
||||
暂无发行版
|
||||
{distribution && <Link className="color-blue ml20" to={{pathname:`/${owner}/${projectsId}
|
||||
new`,state:{stable:true}}}>发布新版本</Link>}
|
||||
{distribution && <Link className="color-blue ml20" to={{pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}}}>发布新版本</Link>}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,25 +5,21 @@ import axios from 'axios';
|
|||
|
||||
const Option = AutoComplete.Option;
|
||||
|
||||
export default ({ getUser , placeholder, width ,value })=>{
|
||||
export default ({ getUser , placeholder, width ,value, userList=[] })=>{
|
||||
const [ source , setSource ] = useState(undefined);
|
||||
const [ searchKey , setSearchKey ] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
if(!value){
|
||||
setSearchKey(undefined);
|
||||
if(userList && userList.length){
|
||||
sourceOptions(userList);
|
||||
}else{
|
||||
getUserList();
|
||||
}
|
||||
},[value])
|
||||
|
||||
useEffect(()=>{
|
||||
getUserList();
|
||||
},[searchKey])
|
||||
},[])
|
||||
|
||||
function getUserList(e){
|
||||
function getUserList(value){
|
||||
const url = `/users/list.json`;
|
||||
axios.get(url, {
|
||||
params: {
|
||||
search: searchKey,
|
||||
search: value,
|
||||
},
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
|
|
@ -61,13 +57,9 @@ export default ({ getUser , placeholder, width ,value })=>{
|
|||
setSource(s);
|
||||
}
|
||||
|
||||
function changeInputUser(e){
|
||||
setSearchKey(e);
|
||||
};
|
||||
|
||||
// 选择用户
|
||||
function selectInputUser(e, option){
|
||||
setSearchKey(option.props.name);
|
||||
getUserList(option.props.name);
|
||||
getUser(option.props.login);
|
||||
};
|
||||
|
||||
|
|
@ -76,12 +68,12 @@ export default ({ getUser , placeholder, width ,value })=>{
|
|||
<AutoComplete
|
||||
getPopupContainer={trigger => trigger.parentNode}
|
||||
dataSource={source}
|
||||
value={searchKey}
|
||||
style={{ width: width || 300 }}
|
||||
onChange={changeInputUser}
|
||||
onSearch={(value)=>{getUserList(value)}}
|
||||
onSelect={selectInputUser}
|
||||
placeholder={placeholder || "搜索需要添加的用户..."}
|
||||
allowClear
|
||||
optionLabelProp="name"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ $(window).scroll(function () {
|
|||
});
|
||||
|
||||
function SiderBar(props) {
|
||||
const {location, history} = props;
|
||||
const {location, history,user} = props;
|
||||
const {search, pathname} = location;
|
||||
const [ data , setData ] = useState([]);
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
|
|
@ -30,9 +30,13 @@ function SiderBar(props) {
|
|||
const [ feedBackValue, setFeedBackValue] = useState(undefined);
|
||||
const [ failApply, setFailApply] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
user && setLogin(user.login);
|
||||
},[user])
|
||||
|
||||
useEffect(()=>{
|
||||
getFAQ();
|
||||
getCurrentUser();
|
||||
// getCurrentUser();
|
||||
//页面加载完成之后隐藏回到顶点
|
||||
$(".-task-sidebar .gotop").hide();
|
||||
// 意见反馈弹窗
|
||||
|
|
@ -51,15 +55,6 @@ function SiderBar(props) {
|
|||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
//获取当前登录账号信息->用于建议反馈
|
||||
function getCurrentUser(){
|
||||
let url = `/users/get_user_info.json`;
|
||||
axios.get(url).then((response) => {
|
||||
if (response && response.data && response.data.login) {
|
||||
setLogin(response.data.login);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
function content(list){
|
||||
return <div>
|
||||
|
|
|
|||
|
|
@ -22,15 +22,15 @@ export default ({ url , name , column , id , login })=>{
|
|||
return(
|
||||
id?
|
||||
<Link to={`/${login}`}>
|
||||
<Img>
|
||||
<span className="User">
|
||||
{ url && <img src={url} alt=""/> }
|
||||
<span>{name}</span>
|
||||
</Img>
|
||||
</span>
|
||||
</Link>
|
||||
:
|
||||
<Img>
|
||||
<span className="User">
|
||||
{ url && <img src={url} alt=""/> }
|
||||
<span>{name}</span>
|
||||
</Img>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import React ,{ Fragment, useEffect } from 'react';
|
||||
import echarts from 'echarts/lib/echarts'
|
||||
import 'echarts/lib/chart/radar';
|
||||
import 'echarts/lib/component/tooltip';
|
||||
import axios from 'axios';
|
||||
import { Icon, Popover } from 'antd';
|
||||
|
||||
function Radar({owner,projectsId}) {
|
||||
|
||||
useEffect(()=>{
|
||||
const url = `/v1/${owner}/${projectsId}/portrait.json`;
|
||||
axios.get(url).then(res=>{
|
||||
if(res && res.data){
|
||||
Init(res.data);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
},[])
|
||||
|
||||
function Init(data) {
|
||||
var huan_val = document.getElementById("projectPortrait");
|
||||
var myEcharts = echarts.init(huan_val);
|
||||
let option = {
|
||||
color: ["#f8e367", "#99dfff", "#58c0f0", "#5ea6ff", "#ff9e48", "#bcbcbc"],
|
||||
title: {
|
||||
show:false
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: (params) =>{
|
||||
const {name, seriesName, value} = params
|
||||
const tips = seriesName.split(",").map((item, index)=>{
|
||||
return `${item}:${(value[index]-20).toFixed(2)}`
|
||||
})
|
||||
return [name].concat(tips).join("<br/>")
|
||||
}
|
||||
},
|
||||
radar: {
|
||||
indicator: [
|
||||
{ name: '社区\n影响力', max: 120},
|
||||
{ name: '项目\n成熟度', max: 120},
|
||||
{ name: '项目\n健康度', max: 120},
|
||||
{ name: '团队\n影响度', max: 120},
|
||||
{ name: '开发\n活跃度', max: 120},
|
||||
],
|
||||
center:["50%","55%"]
|
||||
},
|
||||
series: [{
|
||||
name: "社区影响力,项目成熟度,项目健康度,团队影响度,开发活跃度",
|
||||
type: 'radar',
|
||||
data: [
|
||||
{
|
||||
value: [addTwenty(data.community_impact), addTwenty(data.project_maturity), addTwenty(data.project_health), addTwenty(data.team_impact), addTwenty(data.develop_activity)],
|
||||
name: '本项目评分'
|
||||
},
|
||||
]
|
||||
}]
|
||||
};
|
||||
myEcharts.setOption(option);
|
||||
}
|
||||
|
||||
function addTwenty(number){
|
||||
return Number(number)+20
|
||||
}
|
||||
|
||||
const content = (
|
||||
<div>
|
||||
从以下五个维度生成当前项目画像:<br/>
|
||||
社区影响力:从项目点赞、关注、fork角度生成评分<br/>
|
||||
项目成熟度:从项目疑修、合并请求、提交总数量生成评分<br/>
|
||||
项目健康度:从项目疑修、合并请求、许可证完成度生成评分<br/>
|
||||
团队影响度:从项目团队稳定性、新人增长率生成评分<br/>
|
||||
开发活跃度:从代码提交、疑修及合并请求等开发活动频率生成评分
|
||||
</div>
|
||||
);
|
||||
|
||||
return(
|
||||
<div className='halfs'>
|
||||
<div className="font-16 color-ooo hoverA mb20">
|
||||
项目画像
|
||||
<Popover content={content}>
|
||||
<Icon type="question-circle" theme="filled" className="color-blue ml10 pointer"/>
|
||||
</Popover>
|
||||
</div>
|
||||
<div id="projectPortrait" style={{height:"230px"}}></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Radar;
|
||||
|
|
@ -1,24 +1,34 @@
|
|||
import React, { useState , useEffect } from 'react';
|
||||
import { Button , Table , Tooltip } from 'antd';
|
||||
import { Button , Table , Tooltip, message } from 'antd';
|
||||
import Modals from '../Component/PublicModal/Index';
|
||||
import { AlignCenter } from '../Component/layout';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import paperImg from './image/paperImg.png';
|
||||
import NewModal from './component/new';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getProjectFunc } from '../../services/project'
|
||||
import "./index.scss";
|
||||
import axios from 'axios';
|
||||
|
||||
function Index(props){
|
||||
const { project , match , current_user , projectDetail , getProject } =props;
|
||||
const has_dataset = project && project.has_dataset;
|
||||
const permission = current_user && current_user.login ? (projectDetail && projectDetail.permission):"";
|
||||
const { owner ,projectsId } = match && match.params;
|
||||
const [ dataSource , setDataSource ] = useState([]);
|
||||
const [ empty , setEmpty ] = useState(project && (!project.has_dataset));
|
||||
const [ total , setTotal ] = useState(0);
|
||||
const [ empty , setEmpty ] = useState(!has_dataset);
|
||||
const [ total , setTotal ] = useState(0);
|
||||
const [ page , setPage ] = useState(1);
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
const [ detail , setDetail ] = useState({});
|
||||
const [ delVisible , setDelVisible ] = useState(false);
|
||||
const [ delId , setDelId ] = useState(undefined);
|
||||
const pageSize = 10;
|
||||
|
||||
useEffect(()=>{
|
||||
setEmpty(!has_dataset);
|
||||
},[has_dataset])
|
||||
|
||||
useEffect(()=>{
|
||||
if(!empty){
|
||||
Init();
|
||||
|
|
@ -65,7 +75,7 @@ function Index(props){
|
|||
key:3,
|
||||
width:"10%",
|
||||
render:(value,item)=>{
|
||||
return <Link to={`/${value.login}`}><img src={getImageUrl(`/${value.image_url}`)} alt="" style={{borderRadius:"50%"}} width="32px" height="32px" /></Link>
|
||||
return <Link to={`/${value.login}`}><img src={`${value.image_url}`} alt="" style={{borderRadius:"50%"}} width="32px" height="32px" /></Link>
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -82,24 +92,46 @@ function Index(props){
|
|||
{
|
||||
title:"操作",
|
||||
dataIndex:"url",
|
||||
align:"center",
|
||||
key:6,
|
||||
width:"10%",
|
||||
width:"12%",
|
||||
render:(value,item)=>{
|
||||
return <a href={value} className="color-blue" download={value}>下载</a>
|
||||
return <React.Fragment>
|
||||
<a href={value} className="color-blue" download={value}>下载</a>
|
||||
<a className='color-red ml20' onClick={()=>{setDelVisible(true);setDelId(item.id);}}>删除</a>
|
||||
</React.Fragment>
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
// 添加成功
|
||||
function addFunc(){
|
||||
setEmpty(false);
|
||||
async function addFunc(){
|
||||
setVisible(false);
|
||||
getProject && getProject();
|
||||
const data = await getProjectFunc(owner,projectsId);
|
||||
if (data.data) {
|
||||
getProject(data.data)
|
||||
}
|
||||
setEmpty(false);
|
||||
detail && detail.id && Init();
|
||||
}
|
||||
|
||||
// 确定删除数据集
|
||||
function delDataSetFunc(){
|
||||
if(delId){
|
||||
const url = `/attachments/${delId}.json`;
|
||||
axios.delete(url).then(res=>{
|
||||
if(res){
|
||||
message.info("数据集附件删除");
|
||||
setDelVisible(false);
|
||||
setDelId(undefined);
|
||||
Init();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return(
|
||||
<div className={`dataset`}>
|
||||
<NewModal visible={visible} detail={detail} owner={owner} repo={projectsId} onCancel={()=>setVisible(false)} onOk={addFunc}/>
|
||||
<NewModal visible={visible} detail={detail} owner={owner} repo={projectsId} onCancel={()=>{setVisible(false);}} onOk={addFunc}/>
|
||||
<div className={`mnistData`}>
|
||||
{empty ?
|
||||
<span className="font-16">数据集</span>
|
||||
|
|
@ -140,6 +172,23 @@ function Index(props){
|
|||
</div>
|
||||
:""
|
||||
}
|
||||
|
||||
<Modals
|
||||
visible={delVisible}
|
||||
onCancel={()=>{setDelVisible(false);setDelId(undefined);}}
|
||||
title={"删除附件"}
|
||||
btn={
|
||||
<div>
|
||||
<Button size={'large'} onClick={()=>{setDelVisible(false);setDelId(undefined);}}>取消</Button>
|
||||
<Button type={"danger"} size={"large"} onClick={delDataSetFunc}>确认</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="desc center">
|
||||
<AlignCenter className="descMain">
|
||||
<i className="iconfont icon-jinggao1 mr10 font-20 red"></i>确定删除该文件?</AlignCenter>
|
||||
</div>
|
||||
</Modals>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,9 @@ const { Option } = Select;
|
|||
function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
|
||||
const { getFieldDecorator, validateFields , setFieldsValue } = form;
|
||||
const [ cate , setCate ] = useState(0);
|
||||
const [ value , setValue ] = useState(undefined);
|
||||
|
||||
const [ organizations , setOrganizations ] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
setFieldsValue({goal:cate})
|
||||
},[])
|
||||
|
||||
useEffect(()=>{
|
||||
if(owner && repo && visible===true){
|
||||
getTeam();
|
||||
|
|
@ -25,7 +20,7 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
|
|||
owner_name:undefined,
|
||||
identifier:undefined
|
||||
})
|
||||
setValue(undefined)
|
||||
setCate(0);
|
||||
}
|
||||
},[repo,owner,visible])
|
||||
|
||||
|
|
@ -79,7 +74,6 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
|
|||
};
|
||||
|
||||
function getUser(id){
|
||||
setValue(id);
|
||||
setFieldsValue({
|
||||
owner_name:id
|
||||
})
|
||||
|
|
@ -94,6 +88,7 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
|
|||
okText="确认转移"
|
||||
cancelText={"取消"}
|
||||
centered
|
||||
destroyOnClose={true}
|
||||
>
|
||||
<div className="diverModal">
|
||||
{
|
||||
|
|
@ -113,7 +108,8 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
|
|||
<Form {...layout} colon={false} layout={"horizontal"}>
|
||||
<Form.Item label="转移给:" style={{marginBottom:"0px"}}>
|
||||
{getFieldDecorator("goal",{
|
||||
rules:[]
|
||||
rules:[],
|
||||
initialValue: 0
|
||||
})(
|
||||
<Radio.Group onChange={changeType}>
|
||||
<Radio value={0}>个人</Radio>
|
||||
|
|
@ -128,7 +124,7 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
|
|||
rules:[{required:true,message:"请输入目标用户名"}]
|
||||
})(
|
||||
// <Input placeholder="请输入目标用户" autoComplete={"off"}/>
|
||||
<SearchUser getUser={getUser} width={"100%"} placeholder="请输入目标用户" value={value}/>
|
||||
<SearchUser getUser={getUser} width={"100%"} placeholder="请输入目标用户"/>
|
||||
)}
|
||||
</Form.Item>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import React, { useEffect , useState } from 'react';
|
|||
import './header.scss';
|
||||
|
||||
function Footer(){
|
||||
const [ value , setValue ] = useState(undefined);
|
||||
const [ value , setValue ] = useState(__CLIENT__ ? undefined : defaultSetting && defaultSetting.footer);
|
||||
|
||||
useEffect(()=>{
|
||||
try {
|
||||
var chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
|
||||
let chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
|
||||
setValue(chromesettingArray.footer);
|
||||
} catch (e) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class NewHeader extends Component {
|
|||
}
|
||||
componentDidMount() {
|
||||
// 用personal判断是否需要再次请求settings接口,解决登录注册之后无设置按钮的情况
|
||||
let settings = localStorage.chromesetting&&JSON.parse(localStorage.chromesetting);
|
||||
let settings = localStorage.chromesetting && localStorage.chromesetting !=="undefined" &&JSON.parse(localStorage.chromesetting);
|
||||
if(settings){
|
||||
this.setState({
|
||||
settings
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
cursor: pointer;
|
||||
transition: 1s;
|
||||
.grow_path_type {
|
||||
width: 82px;
|
||||
// width: 82px;
|
||||
height: 58px;
|
||||
// color: black;
|
||||
font-size: 15px;
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ function HeaderPageJCC(props){
|
|||
return(
|
||||
<Tabs.TabPane tab={i.name} key={i.id}>
|
||||
<div className='tab-content'>
|
||||
<Link to={`/zone/${deptId}/newdetail/${i.id}`}><div className='title'>{i.name}</div>
|
||||
<Link to={`/zone/${deptId}/newdetail/${i.id}`}><div className='title_JCC'>{i.name}</div>
|
||||
<p><img src={shijian} alt="" className="mr3 photo" />{i.publishTime}</p>
|
||||
<p className='new_desc'>{i.summary || '-'}</p>
|
||||
<img src={newsList[k].headImg || img1} alt="" height="260px" style={{width:"100%",objectFit:"cover"}}/></Link>
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@
|
|||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.title{
|
||||
.title_JCC{
|
||||
font-size: 20px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { Form , Input , Row , Col, Button } from 'antd';
|
||||
import { Form , Input , Row , Col, Button, message } from 'antd';
|
||||
import '../index.scss';
|
||||
import { postCreateZone } from '../api';
|
||||
import axios from 'axios';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
const phonereg = /^([1][3456789])\d{9}$/
|
||||
|
|
@ -25,10 +26,10 @@ function Apply(props){
|
|||
const zoneApplication = {...values};
|
||||
postCreateZone(zoneApplication).then(response=>{
|
||||
if(response && response.data && response.data.code===200){
|
||||
props.showNotification("提交成功!");
|
||||
message.success("您的专区申请已提交,请耐心等待管理员与您联系!");
|
||||
setTimeout(() => {
|
||||
window.location.href="/";
|
||||
}, 70);
|
||||
}, 1000);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
|
@ -55,6 +56,7 @@ function Apply(props){
|
|||
callback();
|
||||
}):callback();
|
||||
}
|
||||
|
||||
|
||||
|
||||
return(
|
||||
|
|
@ -72,9 +74,12 @@ function Apply(props){
|
|||
label="专区名称"
|
||||
>
|
||||
{getFieldDecorator("name",{
|
||||
rules:[{required:true,message:"请输入专区名称"}]
|
||||
rules:[
|
||||
{required:true,message:"请输入专区名称"},
|
||||
{pattern: /^[a-zA-Z0-9\u4e00-\u9fa5\\_.-]{1,31}$/, message: "长度1-30,支持中文,英文,数字,可包含下划线(_),中划线(-),英文句号(.)"}
|
||||
]
|
||||
})(
|
||||
<Input placeholder="请输入专区名称" maxLength={50} style={{height:"36px"}}/>
|
||||
<Input placeholder="请输入专区名称" maxLength={30} style={{height:"36px"}}/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
|
|
@ -99,18 +104,18 @@ function Apply(props){
|
|||
<Row type="flex" justify="space-between">
|
||||
<Col span={11}>
|
||||
<Form.Item
|
||||
label="专区标识"
|
||||
label="专区英文标识"
|
||||
>
|
||||
{getFieldDecorator("key",{
|
||||
rules:[
|
||||
{ required: true,message:"请输入专区域名标识" },
|
||||
// { required: true,message:"请输入专区域名英文标识" },
|
||||
{ pattern: /^[a-zA-Z][a-zA-Z0-9_-]{0,18}[a-zA-Z]$/, message: "长度2-20,只能包含数字、字母、下划线、中划线,必须以字母开头结尾"},
|
||||
{ validator:checkId }
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
validateFirst: true,
|
||||
})(
|
||||
<Input placeholder="请输入专区域名标识" maxLength={20} style={{height:"36px"}}/>
|
||||
<Input placeholder="请输入专区域名标识,若未填写系统将根据专区名称自动生成" maxLength={20} style={{height:"36px"}}/>
|
||||
)}
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,22 @@
|
|||
import React,{ useState, useEffect } from 'react';
|
||||
import { httpUrl } from '../fetch';
|
||||
|
||||
import img1 from '../img/img1.png';
|
||||
import img2 from '../img/img2.png';
|
||||
import { Button , Anchor } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
import arrowWhite from '../img/zone1/jiantouwhite.png';
|
||||
import xinpian from '../img/zone1/xinpian.png';
|
||||
import system from '../img/zone1/system.png';
|
||||
import chain from '../img/zone1/chain.png';
|
||||
import eda from '../img/zone1/EDA.png';
|
||||
import fu from '../img/zone1/fu.png';
|
||||
import team1 from '../img/zone1/team1.png';
|
||||
import team2 from '../img/zone1/team2.png';
|
||||
import team3 from '../img/zone1/team3.png';
|
||||
import team4 from '../img/zone1/team4.png';
|
||||
import window from '../img/zone1/window.png';
|
||||
import phone from '../img/zone1/phone.png';
|
||||
import line from '../img/zone1/line.png';
|
||||
import zhao from '../img/zone1/zhao.png';
|
||||
import sys from '../img/zone1/sys.png';
|
||||
import vision0 from '../img/vision0.png';
|
||||
import vision1 from '../img/vision1.png';
|
||||
import vision2 from '../img/vision2.png';
|
||||
|
|
@ -14,20 +28,19 @@ import intro4 from '../img/intro4.png';
|
|||
import guideArrow from '../img/guideArrow1.png';
|
||||
import ra from '../img/ra.png'
|
||||
import title from '../img/title.png'
|
||||
import { Link } from 'react-router-dom';
|
||||
import shijian from '../img/shijian.png';
|
||||
import Nodata from '../../Nodata';
|
||||
import Projects from '../Component/projects';
|
||||
import Contributor from '../Component/contributor';
|
||||
import Partner from '../Component/partner';
|
||||
import '../indexZone1.scss'
|
||||
import { getProjectsLists, getPartnerList, getHomePageList, gethomePageDocList } from '../api'
|
||||
import '../indexZone1.scss';
|
||||
import { getProjectsLists, getPartnerList, getHomePageList, gethomePageDocList , getDocList , getSubDocList } from '../api'
|
||||
|
||||
|
||||
function HeaderPage(props){
|
||||
const [ projectList , setProjectList ] = useState(undefined);
|
||||
// const [ projectList , setProjectList ] = useState(undefined);
|
||||
const [ personList , setPersonList ] = useState(undefined);
|
||||
const [ newsList, setNewsList ] = useState(undefined);
|
||||
// const [ newsList, setNewsList ] = useState(undefined);
|
||||
const [ partnerList, setParterList ] = useState(undefined);
|
||||
const [ recruitId, setRecruitId ] = useState(undefined);
|
||||
const [ recruitList, setRecruitList ] = useState(undefined);
|
||||
const [ showAnchor, setShowAnchor ] = useState(false);
|
||||
const { deptId } = props.match.params;
|
||||
const { data, id, temp, history } = props;
|
||||
|
||||
|
|
@ -52,22 +65,43 @@ function HeaderPage(props){
|
|||
{ type: '计划四', plan: '香山贡献参与' }
|
||||
]
|
||||
|
||||
|
||||
const introDetail = [
|
||||
{ title: '能力阶梯', icon: intro1, desc: '成长体系按照开发者从⼊门到进阶再到⾹⼭顶级项⽬设⽴了⽤户能⼒提升的阶梯式真实项⽬' },
|
||||
{ title: '贡献分级', icon: intro2, desc: '所有开源项⽬全部为开芯院开源开放的真实项⽬,开发者参与开源项⽬的所有贡献将作为成长等级、知产授权、加⼊⾼级别项⽬(悬赏、获得offer等)、成为核⼼贡献者的参与 依据' },
|
||||
{ title: '成长认证', icon: intro3, desc: '开发者可以通过完成开源项⽬对应的任务,赢取对应能⼒成长认证,开源项⽬对应的⾼级任务将获得对应等级L2或⾼级别的知识产权授权,同时解锁下⼀级别成长任务' },
|
||||
{ title: '顶级认证', icon: intro4, desc: '参与顶级项⽬“⾹⼭”的贡献者,将获得中国科学院计算技术研究所副所长、研究员,北京开源芯⽚研究院⾸席科学家,RISC-V国际基⾦会理事会成员包云岗签名贡献者证书' }
|
||||
]
|
||||
useEffect(()=>{
|
||||
if(id){
|
||||
// getProjectList();
|
||||
// getNewsList();
|
||||
getPersonList();
|
||||
getPartner();
|
||||
getHomeDocList();
|
||||
}
|
||||
},[id])
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
if(id){
|
||||
getProjectList();
|
||||
getNewsList();
|
||||
getPersonList();
|
||||
getPartner();
|
||||
document.addEventListener("scroll", scroll);
|
||||
if(recruitId){
|
||||
getDocById(recruitId)
|
||||
}
|
||||
},[id])
|
||||
return () => {
|
||||
document.removeEventListener("scroll", scroll);
|
||||
};
|
||||
},[recruitId])
|
||||
|
||||
|
||||
const scroll = () =>{
|
||||
let sTop = document.documentElement.scrollTop;
|
||||
if(sTop >= 2000){
|
||||
setShowAnchor(true);
|
||||
}else{
|
||||
setShowAnchor(false);
|
||||
}
|
||||
}
|
||||
|
||||
function getPersonList(){
|
||||
getHomePageList(id).then(result=>{
|
||||
|
|
@ -76,25 +110,46 @@ function HeaderPage(props){
|
|||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
function getNewsList(){
|
||||
gethomePageDocList(id).then(result=>{
|
||||
if(result){
|
||||
setNewsList(result.data.rows);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}
|
||||
function getProjectList(){
|
||||
getProjectsLists(id,{ isHomepage:1 }).then(result=>{
|
||||
if(result){
|
||||
if (result.data.rows.length < 3) {
|
||||
setProjectList(result.data.rows)
|
||||
} else {
|
||||
setProjectList([...result.data.rows, {}]);
|
||||
// 获取所有栏目,找到招聘专栏拿到其id
|
||||
function getHomeDocList(){
|
||||
getDocList(id).then(result=>{
|
||||
if(result && result.data.rows){
|
||||
let rows = result.data.rows;
|
||||
let filterRow = rows ? rows.filter(i=>i.name === "招聘专栏") : undefined;
|
||||
if(filterRow && filterRow.length>0){
|
||||
setRecruitId(filterRow[0].id);
|
||||
}
|
||||
}
|
||||
}).catch(error=>{})
|
||||
})
|
||||
}
|
||||
// 根据招聘专栏的id获取其栏目下的招聘文章
|
||||
function getDocById(recruitId){
|
||||
getSubDocList(recruitId,{pageSize:4,pageNum:1,auditStatus:1}).then(result=>{
|
||||
if(result && result.data.rows){
|
||||
let rows = result.data.rows;
|
||||
setRecruitList(rows);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// function getNewsList(){
|
||||
// gethomePageDocList(id).then(result=>{
|
||||
// if(result){
|
||||
// setNewsList(result.data.rows);
|
||||
// }
|
||||
// }).catch(error=>{})
|
||||
// }
|
||||
// function getProjectList(){
|
||||
// getProjectsLists(id,{ isHomepage:1 }).then(result=>{
|
||||
// if(result){
|
||||
// if (result.data.rows.length < 3) {
|
||||
// setProjectList(result.data.rows)
|
||||
// } else {
|
||||
// setProjectList([...result.data.rows, {}]);
|
||||
// }
|
||||
// }
|
||||
// }).catch(error=>{})
|
||||
// }
|
||||
|
||||
function getPartner(){
|
||||
getPartnerList(id).then(result => {
|
||||
|
|
@ -115,8 +170,220 @@ function HeaderPage(props){
|
|||
})
|
||||
}
|
||||
return(
|
||||
<div className="zone1_box">
|
||||
{
|
||||
<div className="zone1_box kxy" id="zone1_box">
|
||||
{showAnchor &&
|
||||
<Anchor className='anchor_kxy'>
|
||||
<Anchor.Link href="#system_open" title="开源芯片技术体系" />
|
||||
<Anchor.Link href="#zone_grow" title="开源芯⽚⽤户成长体系" />
|
||||
{recruitList && recruitList.length > 0 && <Anchor.Link href="#zone_communicate" title="招聘专栏"/> }
|
||||
{data && data.partnersShow === 1 && partnerList && partnerList.length > 0 && <Anchor.Link href="#zone_parter" title="合作伙伴"></Anchor.Link>}
|
||||
<Anchor.Link href="#zone_community" title="参与社区"></Anchor.Link>
|
||||
</Anchor>
|
||||
}
|
||||
|
||||
<div className='line_key' id="line_key">
|
||||
<p className="in_title mb20">芯片设计创新链</p>
|
||||
<p className='font-17 mb20'><img src={ra} width={33} className='mr10'/>欢迎开源芯片企业、高校、开发者、学生参与社区</p>
|
||||
<div className='chainBox'>
|
||||
<div className='chainNews'>
|
||||
<li className='skybox'>
|
||||
<span className='boldFont' style={{height:"56px",lineHeight:"56px"}}>FPGA</span><span className='skybox' style={{backgroundColor:"#fff",flex:1}}>商业FPGA</span>
|
||||
</li>
|
||||
<li className='skybox'>
|
||||
<span className='boldFont'>FPGA云平台</span>
|
||||
<span className='greenbox unHover' style={{flex:1,padding:"0px 5px",cursor:'default'}}>服务“香山”的开源FPGA云平台<img src={arrowWhite} width={27}/></span>
|
||||
</li>
|
||||
<div className='chainNews_Main'>
|
||||
<li className='flexCenter mb20'>
|
||||
<span className='boldFont mr20'>SOC</span>
|
||||
<span className='skybox' style={{flex:1}}>常开域:LCLKGEN、WatchDog、PMU、RTC</span>
|
||||
</li>
|
||||
<div className='flex'>
|
||||
<div style={{width:450}} className='left_Infos'>
|
||||
<div className='bord_padding chainNews_Box mb20'>
|
||||
<span className='boldFont mb20'>CORE</span>
|
||||
<li className='greenbox width100'><a href='https://www.gitlink.org.cn/OSchip/xiangshan-intro' target='_blank'>开源高性能 RISC-V 处理器核“香山”<img src={arrowWhite} width={27}/></a></li>
|
||||
<li className='greenbox width45'><a href='https://www.gitlink.org.cn/0Schip/openc906' target='_blank'>玄铁 openC906<img src={arrowWhite} width={27}/></a></li>
|
||||
<li className='greenbox width45 mlauto'><a href='https://www.gitlink.org.cn/OSchip/opene906' target='_blank'>玄铁 openE906<img src={arrowWhite} width={27}/></a></li>
|
||||
<li className='greenbox width45'><a href='https://www.gitlink.org.cn/OSchip/openc910' target='_blank'>玄铁 openC910<img src={arrowWhite} width={27}/></a></li>
|
||||
<li className='greenbox width45 mlauto'><a href='https://www.gitlink.org.cn/OSchip/opene902' target='_blank'>玄铁 openE902<img src={arrowWhite} width={27}/></a></li>
|
||||
<li className='greenbox width100'><a href='https://www.gitlink.org.cn/OSchip/THU-DSP-LAB' target='_blank'>清华大学 乘影开源通用图形处理器<img src={arrowWhite} width={27}/></a></li>
|
||||
<li className='greenbox width45'><a href='https://www.gitlink.org.cn/OSchip/X-Core' target='_blank'>澎峰科技 X-Core<img src={arrowWhite} width={27}/></a></li>
|
||||
<li className='skybox width45 mlauto'>商业闭源核</li>
|
||||
</div>
|
||||
<div className='chainNews_Box'>
|
||||
<li className='skybox width30'>CLINT</li>
|
||||
<li className='greenbox width30 mlauto'><a href='https://mp.weixin.gg.com/s/7cYFBFH7Emkhvc2W48Lgto' target='_blank'>NOC<img src={arrowWhite} width={27}/></a></li>
|
||||
<li className='skybox width30 mlauto'>PLIC</li>
|
||||
<li className='skybox width100'>存储总线(AMBA)</li>
|
||||
<li className='skybox width100'>存储:ROM、SRAM、DRAM、NAND/NOR Flash、DDR</li>
|
||||
</div>
|
||||
</div>
|
||||
<ul className='middle_ul bord_padding14'>
|
||||
<li className='skybox'>AMBA</li>
|
||||
<li className='skybox'>AXI</li>
|
||||
<li className='skybox'>AHB</li>
|
||||
<li className='skybox'>APB</li>
|
||||
</ul>
|
||||
<div style={{width:340}} className='right_infos'>
|
||||
<div className='bord_padding chainNews_Box mb20 '>
|
||||
<span className='boldFont mb20'>开源IP</span>
|
||||
<li className='skybox width30'>UART</li>
|
||||
<li className='skybox width30 mlauto'>SPI</li>
|
||||
<li className='skybox width30 mlauto'>PS2</li>
|
||||
<li className='skybox width30'>VGA</li>
|
||||
<li className='skybox width30 mlauto'>Ethernet</li>
|
||||
<li className='skybox width30 mlauto'>USB2.0</li>
|
||||
<span className='boldFont mb20'>硬件加速卡</span>
|
||||
<li className='greenbox width100'><a href='https://www.gitlink.org.cn/OSchip/Open-rdma' target='_blank'>加速卡:达坦科技 Open-rdma<img src={arrowWhite} width={27}/></a></li>
|
||||
</div>
|
||||
<div className='bord_padding chainNews_Box'>
|
||||
<span className='boldFont mb20'>商用IP</span>
|
||||
<li className='skybox width30'>UART</li>
|
||||
<li className='skybox width30 mlauto'>SPI</li>
|
||||
<li className='skybox width30 mlauto'>GPIO</li>
|
||||
<li className='skybox width30'>VGA</li>
|
||||
<li className='skybox width30 mlauto'>HDMI</li>
|
||||
<li className='skybox width30 mlauto'>DP</li>
|
||||
<li className='skybox width30'>Ethernet</li>
|
||||
<li className='skybox width30 mlauto'>PCle</li>
|
||||
<li className='skybox width30 mlauto'>SATA</li>
|
||||
<li className='skybox' style={{width:190}}>视频编解码(媒体)</li>
|
||||
<li className='skybox width30 ml15'>2D GPU</li>
|
||||
<li className='skybox width30'>3D GPU</li>
|
||||
<li className='skybox width30 ml15'>AI加速器</li>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul>
|
||||
<div><img src={chain}/>工具链</div>
|
||||
<li>
|
||||
<span className='greenbox'><a href='https://www.gitlink.org.cn/terapines/circt' target='_blank'>兆松科技 基于 MLIR 的开源工具链平台circt <img src={arrowWhite} width={27}/></a></span>
|
||||
<span className='greenbox'><a href='https://www.gitlink.org.cn/OSchip/OpenBLAS' target='_blank'>澎峰科技 OpenBLAS 澎峰科技 OpenMPL<img src={arrowWhite} width={27}/></a></span>
|
||||
</li>
|
||||
<li className='skybox'>商业产品</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<div><img src={eda}/>EDA工具链</div>
|
||||
<li>
|
||||
<span className='greenbox'><a href='https://www.gitlink.org.cn/OSchip/iEDA' target='_blank'>iEDA <img src={arrowWhite} className='ml10' width={27}/></a></span>
|
||||
</li>
|
||||
<li className='skybox'>商业产品</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<div><img src={xinpian}/>芯片验证</div>
|
||||
<li>
|
||||
<span className='greenbox'><a href='https://www.gitlink.org.cn/XS-MLVP' target='_blank'>开芯院 UnityChip<img src={arrowWhite} className='ml10' width={27}/></a></span>
|
||||
</li>
|
||||
<li className='skybox'>商业产品</li>
|
||||
</ul>
|
||||
{/* 将后面模块的id置前,以便滚动到当前位置就选中后面模块 */}
|
||||
<div id="system_open"></div>
|
||||
<ul>
|
||||
<div><img src={system}/>操作系统</div>
|
||||
<li>
|
||||
<span className='font-18'><img src={window} width={22} className='mr5'/>桌面端操作系统</span>
|
||||
<span className='greenbox'><a href='https://www.gitlink.org.cn/bianbu-linux' target='_blank'>Bianbu操作系统<img src={arrowWhite} className='ml10' width={27}/></a></span>
|
||||
<span className='skybox'>商业产品</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className='font-18'><img src={phone} width={13} className='mr5'/>AIoT端操作系统</span>
|
||||
<span className='greenbox'><a href='https://www.gitlink.org.cn/OSchip/OpenHarmony' target='_blank'>润开鸿OpenHarmony<img src={arrowWhite} className='ml10' width={27}/></a></span>
|
||||
<span className='skybox'>商业产品</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className='font-18'><img src={fu} width={15} className='mr5'/>服务器操作系统</span>
|
||||
<span className='skybox'>开源产品</span>
|
||||
<span className='skybox'>商业产品</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className='system_open'>
|
||||
<div>
|
||||
<p className="in_title mb20">开源芯片技术体系</p>
|
||||
<div className='flexCenter sys_box'>
|
||||
<p className='font-22' style={{color: "#373F4C",fontWeight:'600',paddingRight:70}}><img src={ra} width={33} className='mr10'/>构建开源芯片生态</p>
|
||||
<p className='font-22' style={{color: "#373F4C",fontWeight:'600'}}><img src={ra} width={33} className='mr10'/>开源芯片的三个层次</p>
|
||||
</div>
|
||||
<img src={sys} alt='' width={"100%"}/>
|
||||
</div>
|
||||
<div className="zone_vision pt60 pb60">
|
||||
<p className="in_title mb40">开源芯片社区OChip宗旨及愿景</p>
|
||||
<div className='boxmain'>
|
||||
{
|
||||
vision.map((i, k) => {
|
||||
return (
|
||||
<div className="vision_item" key={ k }>
|
||||
<div className="vision_icon">
|
||||
<img src={i.imageUrl} alt="" />
|
||||
</div>
|
||||
<p className="vision_title">{ i.title }</p>
|
||||
<p className="vision_content">{ i.content }</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="zone_grow"></div>
|
||||
<div className="zone_grow pt60 pb60">
|
||||
{/* <p className="in_title mb20">开源芯<b>⽚⽤</b>户成长体系介绍</p> */}
|
||||
<p className="in_title mb20"><img src={ title } alt="" /></p>
|
||||
<p className="sub_title">参与开源芯⽚项⽬的开发者需要签署开源贡献者协议</p>
|
||||
<p className="sub_title mb50">建议开发者按照开源项⽬成长路径进⾏参与,稳步提升能⼒,降低跳级参与带来的挑战</p>
|
||||
{/* <div className="grow_path boxmain">
|
||||
{
|
||||
growPathInfo.map((i, k) => {
|
||||
return (
|
||||
<div className="grow_path_item" key={ k }>
|
||||
{ k % 2 === 1 && <div className="dot"></div> }
|
||||
<div className="grow_path_type">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
{ i.type }
|
||||
</div>
|
||||
<p className="grow_path_plan">{ i.plan }</p>
|
||||
{ k % 2 === 0 && <div className="dot"></div> }
|
||||
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div className="line"></div>*/}
|
||||
<div className='grow_content'>
|
||||
<img src={line} width={1250} style={{marginRight:"-50px"}}/>
|
||||
<div className='grow_a'>
|
||||
<a href="https://ysyx.oscc.cc/" target='_blank'></a>
|
||||
<a href="https://datenlord.github.io/zh-cn/#/community/mit" target='_blank' style={{width:"197px"}}></a>
|
||||
<a href="https://open-verify.cc/learningresource/comm/com_001/" target='_blank'></a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grow_introduction boxmain pt40">
|
||||
{
|
||||
introDetail.map((i, k) => {
|
||||
return (
|
||||
<div className="intro_item" key={ k }>
|
||||
<p className="intro_title">
|
||||
<img src={i.icon} alt="" className="mr3" />
|
||||
{ i.title }
|
||||
</p>
|
||||
<p className="intro_desc">{ i.desc }</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div className="dot_line"></div>
|
||||
<div id="zone_communicate"></div>
|
||||
</div>
|
||||
|
||||
{/* {
|
||||
// 专区简介
|
||||
data && (data.introductionTitle || data.introductionContent || data.introductionImage) &&
|
||||
<div className="boxmain zone_infos mb30">
|
||||
|
|
@ -129,26 +396,9 @@ function HeaderPage(props){
|
|||
<img src={data.introductionImage} alt="" width="600px" height="361px"/>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div className="zone_vision pt40 pb60">
|
||||
<p className="in_title mb40">宗旨及愿景</p>
|
||||
<div className='boxmain'>
|
||||
{
|
||||
vision.map((i, k) => {
|
||||
return (
|
||||
<div className="vision_item" key={ k }>
|
||||
<div className="vision_icon">
|
||||
<img src={i.imageUrl} alt="" />
|
||||
</div>
|
||||
<p className="vision_title">{ i.title }</p>
|
||||
<p className="vision_content">{ i.content }</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
} */}
|
||||
|
||||
{/* {
|
||||
// 新闻动态
|
||||
data && data.cmsShow === 1 && newsList && newsList.length>0 &&
|
||||
<div className="zone_news">
|
||||
|
|
@ -195,100 +445,98 @@ function HeaderPage(props){
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
} */}
|
||||
{/* {
|
||||
// 精选项目
|
||||
data && data.projectShow === 1 && projectList && projectList.length > 0 &&
|
||||
<div className="zone_projects pt50 pb30">
|
||||
<p className="in_title mb40">{ data.homepageProjectTitle }</p>
|
||||
<Projects projectList={projectList}></Projects>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
// 核心贡献者
|
||||
data && data.memberShow === 1 && personList && personList.length > 0 &&
|
||||
<div className="zone_contributor">
|
||||
<p className="in_title">{ data.homepageMemberTitle }</p>
|
||||
<Contributor personList={personList}></Contributor>
|
||||
</div>
|
||||
}
|
||||
} */}
|
||||
|
||||
<div className="zone_community pt60 pb60">
|
||||
<p className="in_title mb20">参与社区</p>
|
||||
<p className="sub_title mb50"><img src={ra} alt="" className="mr5" />成为社区成员,尽情发挥您的创意</p>
|
||||
<div className="c_role boxmain">
|
||||
{
|
||||
communityInfo.map((i, k) => {
|
||||
return (
|
||||
<div className="c_role_item" key={ k }>
|
||||
<p className="role_level">{ i.level }</p>
|
||||
<p className="role_todo">{ i.todo }</p>
|
||||
<div className="dot"></div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div className="dot_line"></div>
|
||||
</div>
|
||||
|
||||
<div className="zone_grow pt60 pb60">
|
||||
{/* <p className="in_title mb20">开源芯<b>⽚⽤</b>户成长体系介绍</p> */}
|
||||
<p className="in_title mb20"><img src={ title } alt="" /></p>
|
||||
<p className="sub_title">参与开源芯⽚项⽬的开发者需要签署开源贡献者协议</p>
|
||||
<p className="sub_title mb50">建议开发者按照开源项⽬成长路径进⾏参与,稳步提升能⼒,降低跳级参与带来的挑战</p>
|
||||
<div className="grow_path boxmain">
|
||||
{
|
||||
growPathInfo.map((i, k) => {
|
||||
return (
|
||||
<div className="grow_path_item" key={ k }>
|
||||
{ k % 2 === 1 && <div className="dot"></div> }
|
||||
<div className="grow_path_type">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
{ i.type }
|
||||
{
|
||||
recruitList && recruitList.length > 0 &&
|
||||
<div className="zone_communicate">
|
||||
<p className="in_title">招聘专栏</p>
|
||||
<Link className="joinButton mb30 mt30" to={`/zone/${deptId}/news/${recruitId}`}>查看全部</Link>
|
||||
<ul className='zone_recruit'>
|
||||
<div>
|
||||
<p><img src={zhao} />“职”等你来</p>
|
||||
<p> ——企业招聘专栏</p>
|
||||
<p>在这里,我们汇聚了开源芯片的精英企业,为您带来最前沿的就业机会。加入我们,让梦想照进现实,共同开启职业生涯的新篇章!</p>
|
||||
</div>
|
||||
{
|
||||
recruitList.map((i,k)=>{
|
||||
return(
|
||||
<li>
|
||||
<p className='zone_recruit_name'>{i.name}</p>
|
||||
<p className='zone_recruit_desc'>{i.summary}</p>
|
||||
<Link className='flexCenter zone_recruit_btn' to={`/zone/${deptId}/newdetail/${i.id}`}>查看详情<img src={guideArrow} height={10}/></Link>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
<div className='last_box'>
|
||||
{
|
||||
// 合作伙伴
|
||||
data && data.partnersShow === 1 && partnerList && partnerList.length > 0 &&
|
||||
<div className="zone_parter" id="zone_parter">
|
||||
<p className="in_title">{ data.homepagePartnersTitle }</p>
|
||||
<p className="mb20 shandowTitle">核心企业<span>CORE ENTERPRISE</span></p>
|
||||
<Partner id={ id } partnerList={ partnerList }></Partner>
|
||||
<div><Button href='mailto:anxu@bosc.ac.cn' className='joinButton'>立即加入</Button></div>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
data && data.memberShow === 1 && personList && personList.length > 0 &&
|
||||
<div className='pt40'>
|
||||
<p className="mb40 shandowTitle">核心贡献者<span>CORE CONTRIBUTORS</span></p>
|
||||
<ul className='zone_member'>
|
||||
{personList.map((item,key)=>{
|
||||
return(
|
||||
<li>
|
||||
<img src={item.imageUrl} alt="" />
|
||||
<p className='font-20 weight500'>{item.name}</p>
|
||||
<p className='task-hide '>{item.introduction || "暂无简介"}</p>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
<div className="zone_community" id="zone_community">
|
||||
<p className="mb20 shandowTitle">开发者加入社区<span>DEVELOPERS INCOMING THE COMMUNITY</span></p>
|
||||
{/* <p className="sub_title mb50"><img src={ra} alt="" className="mr5" />成为社区成员,尽情发挥您的创意</p> */}
|
||||
<div className="c_role boxmain">
|
||||
{
|
||||
communityInfo.map((i, k) => {
|
||||
return (
|
||||
<div className="c_role_item" key={ k }>
|
||||
<div className='c_role_div'>
|
||||
<div>
|
||||
<p className="role_level">{ i.level }</p>
|
||||
<p className="role_todo">{ i.todo }</p>
|
||||
</div>
|
||||
{ k === 0 && <img src={team1} alt="" />}
|
||||
{ k === 1 && <img src={team2} alt="" />}
|
||||
{ k === 2 && <img src={team3} alt="" />}
|
||||
{ k === 3 && <img src={team4} alt="" />}
|
||||
</div>
|
||||
<div className="dot"></div>
|
||||
</div>
|
||||
<p className="grow_path_plan">{ i.plan }</p>
|
||||
{ k % 2 === 0 && <div className="dot"></div> }
|
||||
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div className="dot_line"></div>
|
||||
<div><Button href='mailto:anxu@bosc.ac.cn' className='joinButton'>加入社区</Button></div>
|
||||
</div>
|
||||
<div className="line"></div>
|
||||
<div className="grow_introduction boxmain pt40">
|
||||
{
|
||||
introDetail.map((i, k) => {
|
||||
return (
|
||||
<div className="intro_item" key={ k }>
|
||||
<p className="intro_title">
|
||||
<img src={i.icon} alt="" className="mr3" />
|
||||
{ i.title }
|
||||
</p>
|
||||
<p className="intro_desc">{ i.desc }</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div className="dot_line"></div>
|
||||
</div>
|
||||
|
||||
<div className="zone_communicate">
|
||||
<p className="in_title">集萃群智经验 交流心得体会</p>
|
||||
<button onClick={() => { window.location.href = 'https://forum.gitlink.org.cn/forums/theme/135' }}>立即加入</button>
|
||||
</div>
|
||||
{
|
||||
// 合作伙伴
|
||||
data && data.partnersShow === 1 && partnerList && partnerList.length > 0 &&
|
||||
<div className="zone_parter">
|
||||
<p className="in_title">{ data.homepagePartnersTitle }</p>
|
||||
<Partner id={ id } partnerList={ partnerList }></Partner>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,25 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Box, LongWidth, FlexAJ } from '../../Component/layout';
|
||||
import { Affix, Button, Input, message, Spin, Tree } from 'antd';
|
||||
import { Affix, Button, message, Spin } from 'antd';
|
||||
import Nodata from '../../Nodata';
|
||||
import nodata from '../img/nodata.png';
|
||||
import { tempEnum } from '../tempInfo';
|
||||
import { findFirstWiki, generateList, getParentKey, getWiki, parseSidebar, wikiPages } from '../../Wiki/api';
|
||||
import { findNodeByFirstOrContrastName, getMenuListAndSidebarData, getWiki } from '../../Wiki/api';
|
||||
import RenderHtml from '../../../components/render-html';
|
||||
import { Base64 } from 'js-base64';
|
||||
import { getTocContent } from '../../../common/marked';
|
||||
import { splitAndCombine } from '../../Wiki/utils';
|
||||
|
||||
const { Search } = Input;
|
||||
const { DirectoryTree, TreeNode } = Tree;
|
||||
import TreeByWikiSidebar from '../../Wiki/components/treeByWikiSidebar';
|
||||
|
||||
function ProjectSource(props) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [wikiList, setWikiList] = useState(undefined);
|
||||
const [flattenedMenuList, setFlattenedMenuList] = useState([]);
|
||||
const [initMenuList, setInitMenuList] = useState([]);
|
||||
const [expandedKeys, setExpandedKeys] = useState(undefined);
|
||||
const [wikiPageInitDetail, setWikiPageInitDetail] = useState({})
|
||||
const [wiki, setWiki] = useState(undefined);
|
||||
const [wikiDetail, setWikiDetail] = useState(undefined);
|
||||
const [autoExpandParent, setAutoExpandParent] = useState(false);
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
const [wikiContMenu, setWikiContMenu] = useState(undefined);
|
||||
const { temp, history, data, adminUrl } = props;
|
||||
const { temp, history, data, adminUrl, match:{params:{deptId}}, location} = props;
|
||||
const {menuList=[], sidebar="", wikiPages=undefined} = wikiPageInitDetail;
|
||||
const search = new URLSearchParams(location.search);
|
||||
const wikiBySearch = search.get("wiki") || '';
|
||||
let scroller = undefined;
|
||||
|
||||
const { owner, identifier, projectId } = (data && data.gitlinkProject) || {};
|
||||
|
|
@ -38,26 +33,22 @@ function ProjectSource(props) {
|
|||
useEffect(() => {
|
||||
if(!owner) return
|
||||
// 获取wiki 列表
|
||||
wikiPages(wikiParams).then(async res => {
|
||||
if (res && res.message === "200") {
|
||||
setWikiList(res.data);
|
||||
// 解析sidebar获取目录list
|
||||
const info = await parseSidebar(res.data, wikiParams);
|
||||
if (!info) return
|
||||
const { menuList } = info;
|
||||
// 默认打开第一个wiki
|
||||
const firstWiki = findFirstWiki(menuList);
|
||||
if(firstWiki){
|
||||
setExpandedKeys(splitAndCombine(firstWiki.key+""));
|
||||
setWiki(firstWiki);
|
||||
}
|
||||
setFlattenedMenuList(generateList(menuList));
|
||||
setInitMenuList(menuList);
|
||||
} else {
|
||||
setWikiList([]);
|
||||
}
|
||||
getMenuListAndSidebarData(wikiParams).then(res=>{
|
||||
setWikiPageInitDetail(res);
|
||||
})
|
||||
}, [owner])
|
||||
|
||||
useEffect(()=>{
|
||||
if(!menuList.length) return
|
||||
// 通过路由直接访问
|
||||
let node = findNodeByFirstOrContrastName(menuList, wikiBySearch)
|
||||
// 有可能wikiBySearch是错误的值,导致右侧显示为空
|
||||
if(!node){
|
||||
history.push(`/zone/${deptId}/help`)
|
||||
return
|
||||
}
|
||||
setWiki(node);
|
||||
}, [menuList, wikiBySearch])
|
||||
|
||||
useEffect(() =>{
|
||||
if(!wiki){
|
||||
|
|
@ -70,7 +61,7 @@ function ProjectSource(props) {
|
|||
...wikiParams
|
||||
}).then(res=>{
|
||||
setLoading(false);
|
||||
if (res && res.message === "200") {
|
||||
if (res && res.code === 200) {
|
||||
setWikiDetail(res.data);
|
||||
const tocContent = getTocContent();
|
||||
setWikiContMenu(tocContent);
|
||||
|
|
@ -154,77 +145,28 @@ function ProjectSource(props) {
|
|||
};
|
||||
}, [])
|
||||
|
||||
function changeSearchValue(value) {
|
||||
if (value) {
|
||||
const va = value.trim();
|
||||
// 找到命中搜索的item的父元素
|
||||
const expandedKeys = flattenedMenuList.map(item => {
|
||||
if (item.title.match(new RegExp(va, 'i'))) {
|
||||
return getParentKey(item.key, initMenuList);
|
||||
}
|
||||
return null;
|
||||
}).filter((item, i, self) => item && self.indexOf(item) === i);
|
||||
setSearchValue(va);
|
||||
setExpandedKeys(splitAndCombine(expandedKeys[0]));
|
||||
} else {
|
||||
setSearchValue("");
|
||||
}
|
||||
}
|
||||
|
||||
// 收起展开
|
||||
function onExpand(expandedKeys) {
|
||||
setAutoExpandParent(false);
|
||||
setExpandedKeys(expandedKeys);
|
||||
}
|
||||
|
||||
// 选中节点
|
||||
function selectTree(keys,event){
|
||||
let {isFile} = event.node.props.dataRef;
|
||||
if(isFile){
|
||||
setWiki(event.node.props.dataRef);
|
||||
}
|
||||
}
|
||||
|
||||
function renderTreeNodes(data) {
|
||||
return data && data.length > 0 && data.map((item) => {
|
||||
const matchResult = item.titleStr.match(new RegExp(searchValue, 'i'));
|
||||
const title = matchResult ? (
|
||||
<span>
|
||||
{item.titleStr.substr(0, matchResult.index)}
|
||||
<span style={{ color: '#f50' }}>{item.titleStr.substring(matchResult.index, matchResult.index+searchValue.length)}</span>
|
||||
{item.titleStr.substr(matchResult.index+searchValue.length)}
|
||||
</span>
|
||||
) : (
|
||||
<span>{item.titleStr}</span>
|
||||
);
|
||||
return (
|
||||
<TreeNode title={title} key={item.key + ""} isLeaf={item.isFile} dataRef={item} className='menuHcNode font-15'>
|
||||
{renderTreeNodes(item.children)}
|
||||
</TreeNode>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const noDataText = adminUrl ? <a href={`${data && data.gitlinkProject.wiki_url}`} target="_blank" style={{color: '#466aff'}}>前往配置</a> : "正在建设中,敬请期待"
|
||||
const noDataText = adminUrl ? <a href={`${data && data.gitlinkProject.wiki_url}`} target="_blank" className='zone_apply_button'>前往配置</a> : "正在建设中,敬请期待"
|
||||
return (
|
||||
<div className="in_pro">
|
||||
<div className="boxmain" style={{ paddingTop: "56px" }}>
|
||||
<p className="in_title mb30">{data && data.sectionHelperTitle}</p>
|
||||
<Spin spinning={loading}>
|
||||
<Spin spinning={loading} wrapperClassName='themeSpin'>
|
||||
{
|
||||
wikiList && (wikiList.length > 0 ? <Box className='zoneHelpBox'>
|
||||
wikiPages && (wikiPages.length > 0 ? <Box className='zoneHelpBox'>
|
||||
{/* wiki目录导航 */}
|
||||
<div className='leftMenuBox mr20'>
|
||||
<div className='leftMenuHC'>
|
||||
<Search
|
||||
allowClear
|
||||
placeholder="输入关键字搜索文件"
|
||||
className="searchHC mb10"
|
||||
onSearch={changeSearchValue}
|
||||
/>
|
||||
<DirectoryTree onSelect={selectTree} expandedKeys={expandedKeys} onExpand={onExpand} autoExpandParent={autoExpandParent} showIcon={false}>
|
||||
{renderTreeNodes(initMenuList)}
|
||||
</DirectoryTree>
|
||||
<TreeByWikiSidebar
|
||||
wikiParams={wikiParams}
|
||||
hasPermission={false}
|
||||
wikiPageInitDetail={wikiPageInitDetail}
|
||||
clickNode={(node)=>{
|
||||
history.push(`/zone/${deptId}/help?wiki=${encodeURIComponent(node.titleStr)}`)
|
||||
}}
|
||||
history={history}
|
||||
hasOpen={false}
|
||||
searchClassName="searchHC mb10"
|
||||
treeNodeClassName="menuHcNode"/>
|
||||
</div>
|
||||
</div>
|
||||
{/* 内容区 */}
|
||||
|
|
@ -233,12 +175,12 @@ function ProjectSource(props) {
|
|||
<LongWidth>
|
||||
<FlexAJ style={{alignItems: 'stretch'}}>
|
||||
<div>
|
||||
<div className='wikiTitleHC font-20 mb5'>{wikiDetail.name}</div>
|
||||
{wikiDetail.commit && <div className='wikiUpdateTimeHC font-15'>更新时间:{wikiDetail.commit.author.date || '刚刚'}</div>}
|
||||
<div className='wikiTitleHC font-20 mb5'>{wikiDetail.title}</div>
|
||||
{wikiDetail.last_commit && <div className='wikiUpdateTimeHC font-15'>更新时间:{wikiDetail.last_commit.author.date || '刚刚'}</div>}
|
||||
</div>
|
||||
{adminUrl && <Button onClick={()=>{wiki && window.open(`${data && data.gitlinkProject.wiki_url}/${wiki.title_sub}/${wiki.key}`)}} className='zone_apply_button' style={{width: '90px', height: '34px'}}>配置内容</Button>}
|
||||
{adminUrl && <Button onClick={()=>{wiki && window.open(`${data && data.gitlinkProject.wiki_url}?wiki=${encodeURIComponent(wikiDetail.title)}`)}} className='zone_apply_button' style={{width: '90px', height: '34px'}}>配置内容</Button>}
|
||||
</FlexAJ>
|
||||
{wikiDetail.md_content && <RenderHtml className="wikiContentHC editor-content-panel mt20 imageLayerParent" value={ Base64.decode(wikiDetail.md_content) } url={history.location}/>}
|
||||
{wikiDetail.content_base64 && <RenderHtml className="wikiContentHC editor-content-panel mt20 imageLayerParent" value={ Base64.decode(wikiDetail.content_base64) } url={history.location}/>}
|
||||
</LongWidth>
|
||||
{wikiContMenu && wikiContMenu !== "<ul></ul>" && <Affix offsetTop={80}>
|
||||
<div id="wikiContMenuBox" className='wikiContMenuBox font-15' dangerouslySetInnerHTML={{ __html: wikiContMenu }}></div>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ function Main(props){
|
|||
const { deptId , cateId } = props.match.params;
|
||||
const { id, temp, role, history, sectionCmsTitle } = props;
|
||||
|
||||
|
||||
const menu = (
|
||||
<Menu>
|
||||
<Menu.Item>
|
||||
|
|
@ -82,9 +83,10 @@ function Main(props){
|
|||
if(result){
|
||||
let rows = result.data.rows;
|
||||
setMainList(rows);
|
||||
if (temp !== tempEnum.zone) {
|
||||
selectCate(rows[0].id)
|
||||
}
|
||||
// 隐藏判断原因:首页查看全部跳转过来后要默认选择指定的cateID而不是第一个
|
||||
// if (temp !== tempEnum.zone) {
|
||||
selectCate(cateId || (rows[0] && rows[0].id))
|
||||
// }
|
||||
setIsSpin(false);
|
||||
}
|
||||
}).catch(error=>{})
|
||||
|
|
@ -116,6 +118,7 @@ function Main(props){
|
|||
props.history.push(`/zone/${deptId}/news/${id}`)
|
||||
}
|
||||
|
||||
|
||||
return(
|
||||
<div>
|
||||
<div className="main_content">
|
||||
|
|
@ -151,7 +154,7 @@ function Main(props){
|
|||
mainList.map((i,k)=>{
|
||||
if (k <= 4) {
|
||||
return(
|
||||
<div className={`main_tag_item task-hide ${newCateId === i.id ? 'main_tag_selected' : ''}`} key={`${i.id}`} onClick={() => selectCate(i.id)} >{i.name}</div>
|
||||
<div className={`main_tag_item task-hide ${+newCateId === i.id ? 'main_tag_selected' : ''}`} key={`${i.id}`} onClick={() => selectCate(i.id)} >{i.name}</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -60,14 +60,15 @@ function NewsCreate(props){
|
|||
function getNewsDetail() {
|
||||
getNewsDetailByAu(newsId).then(res=>{
|
||||
if(res && res.data){
|
||||
const {name, summary, cmsDir, content, headImg, editorType} = res.data.data;
|
||||
const {name, summary, cmsDir, content, headImg, editorType, keywords} = res.data.data;
|
||||
setType(editorType === "rich_editor" ? 'richEditor' : 'mdEditor')
|
||||
setFieldsValue({
|
||||
name,
|
||||
summary,
|
||||
dirId: cmsDir && cmsDir.id,
|
||||
content: Base64.decode(content),
|
||||
headImg
|
||||
headImg,
|
||||
keywords
|
||||
});
|
||||
setImageUrl(headImg);
|
||||
setValue(Base64.decode(content));
|
||||
|
|
@ -84,12 +85,15 @@ function NewsCreate(props){
|
|||
hasContent && setFields({content: {value:fieldsValue.content,errors:[new Error('请输入内容!')]}});
|
||||
return;
|
||||
}
|
||||
if (fieldsValue.keywords) {
|
||||
fieldsValue.keywords = fieldsValue.keywords.replaceAll(',', ',')
|
||||
}
|
||||
setLoading(true);
|
||||
const params = {
|
||||
...fieldsValue,
|
||||
editorType: type === "richEditor" ? "rich_editor" : "markdown_editor",
|
||||
headImg: imageUrl,
|
||||
content: Base64.encode(fieldsValue.content)
|
||||
content: Base64.encode(fieldsValue.content),
|
||||
}
|
||||
if(isEdit){
|
||||
delete params.editorType;
|
||||
|
|
@ -157,6 +161,13 @@ function NewsCreate(props){
|
|||
</Select>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="文章标签">
|
||||
{getFieldDecorator("keywords", {
|
||||
rules:[{type: 'string', max: 30, message: "请精简文章标签,最大长度30"}],
|
||||
})(
|
||||
<Input placeholder="请输入关键词作为文章标签,使用逗号分隔" maxLength={ 30 } width="220px"/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="内容" wrapperCol={{span: 21}}>
|
||||
{getFieldDecorator("content",{
|
||||
rules:[{required:true,message:"请输入内容!"}],
|
||||
|
|
|
|||
|
|
@ -70,9 +70,9 @@ function NewsDetail(props){
|
|||
document.title= zonedetail.name;
|
||||
setSeoMeta(`${zonedetail.name}`, zonedetail.name, zonedetail.subTitle, `/zone/${deptId}`)
|
||||
} else {
|
||||
const { name, cmsDir, summary, id} = detail;
|
||||
let { name, cmsDir, summary, id, keywords} = detail;
|
||||
const title = `${ name }/${ cmsDir.name }`;
|
||||
const keywords = `${ name },${ cmsDir.name },${ zonedetail.name }`;
|
||||
keywords = keywords || `${ name },${ cmsDir.name },${ zonedetail.name }`;
|
||||
document.title = title;
|
||||
setSeoMeta(keywords, title, summary, `/zone/${deptId}/newdetail/${ id }`)
|
||||
}
|
||||
|
|
@ -129,11 +129,13 @@ function NewsDetail(props){
|
|||
{ detail.auditStatus === '2' && <li><Badge color={temp === "zone" ? "#466aff" : "#089f7f"} text="待审核" className='pass'/></li>}
|
||||
{ detail.auditStatus === '0' && <li><Badge color="#eb1212" text="未通过" className='failed'/></li>}
|
||||
</ul>
|
||||
{ detail.keywords && <div className='keywords'>文章标签:{ detail.keywords.split(',').map(e => (
|
||||
<span>{ e }</span>
|
||||
)) }</div>}
|
||||
</div>
|
||||
{ !isPhone() && <Divider dashed={true} /> }
|
||||
{
|
||||
content ?
|
||||
<RenderHtml className="informations_detail imageLayerParent" value={content} url={props.history.location} />
|
||||
content ? <RenderHtml className="informations_detail imageLayerParent" value={content} url={props.history.location} />
|
||||
:
|
||||
<span>暂无详情~</span>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ function NewsList(props){
|
|||
const [ menuSpin , setMenuSpin ] = useState(true);
|
||||
const { id, temp } = props;
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
if(id && cateId ){
|
||||
setMenuSpin(true);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ function SelfList(props){
|
|||
const pathname = props.location.pathname;
|
||||
const { deptId} = props.match.params;
|
||||
const { id , temp , data } = props;
|
||||
const { sectionCmsTitle } = data;
|
||||
// const { sectionCmsTitle } = data;
|
||||
const sectionCmsTitle = data && data.sectionCmsTitle;
|
||||
const limit = 15;
|
||||
|
||||
useEffect(()=>{
|
||||
|
|
|
|||
|
|
@ -53,6 +53,30 @@ export function getPartnerList(id){
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
export function getDocList(id){
|
||||
return fetch({
|
||||
url:`/cms/doc/open/zone/${id}/dirList`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export function getSubDocList(id,params){
|
||||
return fetch({
|
||||
url:`/cms/doc/open/dir/${id}/docList`,
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 专区会员
|
||||
export function getVIPAllList(id){
|
||||
return fetch({
|
||||
url:`/zone/open/${id}/member/overviewList`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**领域资讯 */
|
||||
export function getNewsAllList(id,params){
|
||||
return fetch({
|
||||
|
|
@ -312,4 +336,54 @@ export function getDataSetdetail(datasetId,params) {
|
|||
method: 'GET',
|
||||
params
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 获取已开通企业的组织列表
|
||||
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',
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -6,6 +6,7 @@ function beforeFetch(actionUrl){
|
|||
axios.defaults.withCredentials = true;
|
||||
}
|
||||
const config = {
|
||||
// headers:{Authorization:"Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjo0NCwidXNlcl9rZXkiOiI3NWY3MmJmYmE2NGU4N2U3NWVjNWMwZDk2OThkMDFiN2EyODE0YjYwIiwidXNlcm5hbWUiOiJpbm5vdiJ9.IviAyZQjPFc4rT3ejAKfJYx3_QgS78RCKHx1XS-A4uI_mrc7_l6wK76HVIoPCEvP0Qimzyc6dpeVW4cE2fILZw"},
|
||||
baseURL: actionUrl,
|
||||
timeout: 1800000, // 请求超时时间
|
||||
}
|
||||
|
|
@ -47,9 +48,9 @@ function beforeFetch(actionUrl){
|
|||
)
|
||||
return service;
|
||||
}
|
||||
let settings = localStorage.chromesetting&&JSON.parse(localStorage.chromesetting);
|
||||
let settings = localStorage.chromesetting&& localStorage.chromesetting !=="undefined"&& JSON.parse(localStorage.chromesetting);
|
||||
let actionUrl = settings && settings.common.zone +'/api';
|
||||
|
||||
const service = beforeFetch(actionUrl);
|
||||
export const httpUrl = actionUrl;
|
||||
export default service;
|
||||
export default service;
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 302 KiB |
|
After Width: | Height: | Size: 807 B |
|
After Width: | Height: | Size: 924 B |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 528 B |
|
After Width: | Height: | Size: 235 B |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 340 KiB |
|
After Width: | Height: | Size: 504 B |
|
After Width: | Height: | Size: 501 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 588 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -111,6 +111,9 @@ function Index(props){
|
|||
const {current_user} = props;
|
||||
|
||||
useEffect(()=>{
|
||||
if(deptId && deptId === "KYDS7th"){
|
||||
window.location.href = 'https://gitlink.org.cn/competitions/2024';
|
||||
}
|
||||
if(deptId && deptId!=="apply"){
|
||||
getDetail();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.themeSpin .ant-spin-dot-item{
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.information_main{
|
||||
background-color:#f3f5f8;
|
||||
min-height: 100vh;
|
||||
|
|
@ -487,6 +491,21 @@
|
|||
background-image:linear-gradient(180deg,#f8f9fd 0%,#f8f9fd 100%);
|
||||
border:1px solid #ffffff;
|
||||
box-sizing: border-box;
|
||||
.keywords {
|
||||
color: #232b3f;
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
margin-top: 10px;
|
||||
span {
|
||||
display: inline-block;
|
||||
background-color: #eff2ff;
|
||||
border-radius: 4px;
|
||||
padding: 0 10px;
|
||||
color: #466aff;
|
||||
margin-right: 5px;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.info_text_main{
|
||||
margin-bottom: 2em;
|
||||
|
|
@ -553,6 +572,20 @@
|
|||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
padding:30px 35px 50px;
|
||||
.keywords {
|
||||
color: #232b3f;
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
margin-top: 10px;
|
||||
span {
|
||||
display: inline-block;
|
||||
background-color: #eff2ff;
|
||||
border-radius: 4px;
|
||||
padding: 0 10px;
|
||||
color: #466aff;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.info_text_main{
|
||||
.i_name{
|
||||
color:#1f2329;
|
||||
|
|
@ -1135,7 +1168,6 @@
|
|||
}
|
||||
}
|
||||
.zone_parter{
|
||||
background-color: #fff;
|
||||
padding:70px 0px 90px;
|
||||
.zone_part_lists{
|
||||
display: flex;
|
||||
|
|
@ -1146,6 +1178,7 @@
|
|||
justify-content: flex-start;
|
||||
align-items: flex-end;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 20px!important;
|
||||
.zone_part_item {
|
||||
color:#1f2329;
|
||||
font-size:20px;
|
||||
|
|
@ -1157,14 +1190,19 @@
|
|||
display: inline-block;
|
||||
width: 200px;
|
||||
}
|
||||
&:nth-child(6n) {
|
||||
a,div{
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
a, div {
|
||||
display: inline-block;
|
||||
width: 220px;
|
||||
height: 88px;
|
||||
line-height: 88px;
|
||||
margin-right: 20px;
|
||||
width: 180px;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
margin-right: 24px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 30px!important;
|
||||
margin-bottom: 25px!important;
|
||||
color:#1f2329;
|
||||
font-size:20px;
|
||||
text-align: center;
|
||||
|
|
@ -1173,8 +1211,8 @@
|
|||
box-shadow:0px 0px 15px rgba(28, 48, 175, 0.08);
|
||||
transition: 0.1s linear;
|
||||
img{
|
||||
max-width: 180px;
|
||||
max-height: 66px;
|
||||
max-width: 160px;
|
||||
max-height: 60px;
|
||||
}
|
||||
&:hover {
|
||||
transform: translate(0, -5px);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
|
||||
.zone1_box{
|
||||
padding-top:70px;
|
||||
background-color:#f7f9fc;
|
||||
.zone_infos{
|
||||
display: flex;
|
||||
|
|
@ -34,7 +33,6 @@
|
|||
}
|
||||
}
|
||||
.zone_vision {
|
||||
background-color: #ffffff;
|
||||
.boxmain {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
|
@ -349,10 +347,10 @@
|
|||
}
|
||||
}
|
||||
.zone_community {
|
||||
background-color:#ebeff5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding:30px 0px 60px;
|
||||
.sub_title {
|
||||
font-size: 17px;
|
||||
line-height: 27px;
|
||||
|
|
@ -366,22 +364,39 @@
|
|||
justify-content: space-between;
|
||||
z-index: 10;
|
||||
.c_role_item {
|
||||
width: 260px;
|
||||
height: 213px;
|
||||
width: 289px;
|
||||
height: 243px;
|
||||
background-image: url(./img/cbg2.png);
|
||||
background-size: 100% 100%;
|
||||
position: relative;
|
||||
padding: 30px 23px;
|
||||
.c_role_div{
|
||||
display: flex;
|
||||
padding:20px;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
img{
|
||||
width: 58px;
|
||||
}
|
||||
}
|
||||
&:first-child{
|
||||
margin-left: -15px;
|
||||
}
|
||||
&:last-child{
|
||||
margin-right: -15px;
|
||||
}
|
||||
.role_level {
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
line-height: 27px;
|
||||
text-align: left;
|
||||
}
|
||||
.role_todo {
|
||||
color: #3d485d;
|
||||
font-size: 15px;
|
||||
line-height: 27px;
|
||||
margin-top: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
.dot {
|
||||
width:14px;
|
||||
|
|
@ -389,8 +404,8 @@
|
|||
border-radius: 50%;
|
||||
background-color:#07a583;
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
bottom: 7px;
|
||||
left: 20px;
|
||||
bottom: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -398,7 +413,7 @@
|
|||
height: 0px;
|
||||
width: 1200px;
|
||||
border-bottom: dashed 1px #8d95ac;
|
||||
transform: translate(0, -14px);
|
||||
transform: translate(0, -28px);
|
||||
}
|
||||
}
|
||||
.zone_grow {
|
||||
|
|
@ -470,6 +485,25 @@
|
|||
border-bottom: solid 1px #07a583;
|
||||
transform: translate(0, -80px);
|
||||
}
|
||||
.grow_content{
|
||||
position: relative;
|
||||
.grow_a{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
height: 100%;
|
||||
padding-top: 60px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 20px;
|
||||
a{
|
||||
display: block;
|
||||
height: 38px;
|
||||
width: 145px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.grow_introduction {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
|
@ -481,6 +515,7 @@
|
|||
box-shadow: 0px 0px 12px rgba(29, 72, 129, 0.08);
|
||||
padding: 22px 17px;
|
||||
transition: 0.1s;
|
||||
text-align: left;
|
||||
.intro_title {
|
||||
font-weight: 700;
|
||||
color: #3d485d;
|
||||
|
|
@ -501,15 +536,15 @@
|
|||
transform: translate(0, -20px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.zone_communicate {
|
||||
height: 160px;
|
||||
height: 547px;
|
||||
background: url('./img/communicateBg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
padding:37px 0px;
|
||||
p {
|
||||
font-weight: 500;
|
||||
font-size: 22px;
|
||||
|
|
@ -524,6 +559,77 @@
|
|||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
margin:16px 0px 48px!important;
|
||||
}
|
||||
.zone_recruit{
|
||||
display: flex;
|
||||
width: 1200px;
|
||||
margin:0px auto;
|
||||
align-items: flex-start;
|
||||
&>div{
|
||||
max-width: 267px;
|
||||
text-align: left;
|
||||
p{
|
||||
&:last-child{
|
||||
font-family:PingFang SC;
|
||||
color:#ffffff;
|
||||
font-size:15px;
|
||||
line-height:36px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
li{
|
||||
background: #ffffff;
|
||||
border-radius: 11px;
|
||||
margin-left: 20px;
|
||||
padding:28px 16px;
|
||||
text-align: left;
|
||||
flex: 1;
|
||||
&:hover{
|
||||
background: #e4eaf2;
|
||||
border-radius: 11px;
|
||||
box-shadow: 0px 0px 10px rgba(7, 70, 165, 0.11);
|
||||
.zone_recruit_btn img{
|
||||
left:68px;
|
||||
}
|
||||
}
|
||||
.zone_recruit_name{
|
||||
font-weight:700;
|
||||
color:#1f2329;
|
||||
font-size:18px;
|
||||
line-height:27px;
|
||||
height:27px;
|
||||
}
|
||||
.zone_recruit_desc{
|
||||
color:#3d485d;
|
||||
font-size:15px;
|
||||
line-height:30px;
|
||||
height: 120px;
|
||||
margin:16px 0px 6px!important;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 4;
|
||||
word-break: break-all;
|
||||
white-space:break-spaces;
|
||||
}
|
||||
.zone_recruit_btn{
|
||||
padding-right: 20px;
|
||||
position: relative;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
color: #07a583;
|
||||
transition: 0.1s;
|
||||
img{
|
||||
position: absolute;
|
||||
left: 62px;
|
||||
top:5px;
|
||||
transition: 0.1s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -648,6 +754,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.line_key{
|
||||
background-color: #fff;
|
||||
padding:70px 0px;
|
||||
}
|
||||
.zone1_source_box{
|
||||
padding-bottom: 30px;
|
||||
.source_h{
|
||||
|
|
@ -766,4 +876,353 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.kxy{
|
||||
text-align: center;
|
||||
position: relative;
|
||||
.zone_member{
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-end;
|
||||
flex-wrap: wrap;
|
||||
width: 1200px;
|
||||
margin:0px auto;
|
||||
li{
|
||||
width: 240px;
|
||||
height: 124px;
|
||||
background-image: url(./img/zone1/core.png);
|
||||
background-size: 100%;
|
||||
margin-right: 80px;
|
||||
box-shadow: 0px 0px 15px rgba(28, 48, 175, 0.08);
|
||||
border-radius: 2px;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
color: #4C5876;
|
||||
margin-bottom: 45px!important;
|
||||
padding:0px 10px;
|
||||
img{
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background: #D8D8D8;
|
||||
box-shadow: 0px 0px 6px 1px rgba(0,0,0,0.08);
|
||||
border: 1px solid #FFFFFF;
|
||||
border-radius: 50%;
|
||||
margin-top: -25px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
&:nth-child(4n){
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.zone_parter{
|
||||
padding-bottom: 0px;
|
||||
.zone_part_lists{
|
||||
margin-top: 0px;
|
||||
}
|
||||
}
|
||||
// 上面纵向的三部分
|
||||
.chainBox{
|
||||
width: 1200px;
|
||||
margin:0px auto;
|
||||
.chainNews{
|
||||
display: flex;
|
||||
&>li{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 8%;
|
||||
margin-right: 18px;
|
||||
padding:15px;
|
||||
}
|
||||
&>ul:last-child{
|
||||
width: 84%;
|
||||
}
|
||||
}
|
||||
.chainNews_Main{
|
||||
flex: 1;
|
||||
border: 1px dashed rgba(70, 106, 255, 0.5);
|
||||
padding:22px;
|
||||
color:#111111;
|
||||
font-size:16px;
|
||||
.left_Infos{
|
||||
li{
|
||||
padding:10px 13px;
|
||||
margin-bottom: 18px!important;
|
||||
}
|
||||
}
|
||||
.right_infos{
|
||||
li{
|
||||
margin-bottom: 18px!important;
|
||||
font-size: 16px;
|
||||
padding:3px 5px!important;
|
||||
}
|
||||
}
|
||||
.middle_ul{
|
||||
width: 110px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
margin:0px auto;
|
||||
}
|
||||
.chainNews_Box{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.boldFont{
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 下面横向排列的三部分
|
||||
&>ul{
|
||||
border: 1px dashed rgba(70, 106, 255, 0.5);
|
||||
padding:15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 18px;
|
||||
color: #111111;
|
||||
&>div{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 150px;
|
||||
padding-left: 25px;
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
img{
|
||||
width: 22px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
&>li{
|
||||
flex:1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-left: 50px;
|
||||
font-size: 16px;
|
||||
&>span{
|
||||
margin-bottom: 20px!important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:last-child{
|
||||
margin-bottom: 0px!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bord_padding{
|
||||
border: 1px dashed rgba(70, 106, 255, 0.5);
|
||||
padding:5px 22px;
|
||||
}
|
||||
.bord_padding14{
|
||||
border: 1px dashed rgba(70, 106, 255, 0.5);
|
||||
padding:14px;
|
||||
}
|
||||
.boldFont{
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
line-height: 27px;
|
||||
}
|
||||
.width30{
|
||||
width: 30%;
|
||||
}
|
||||
.width60{
|
||||
width: 60%;
|
||||
}
|
||||
.mlauto{
|
||||
margin-left: auto;
|
||||
}
|
||||
.width45{
|
||||
width: 45%;
|
||||
}
|
||||
.flex{
|
||||
display: flex;
|
||||
}
|
||||
.skybox{
|
||||
background: #eff2fb;
|
||||
padding:3px 15px;
|
||||
border: 1px dashed rgba(70, 106, 255, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
word-break: break-all;
|
||||
}
|
||||
.greenbox{
|
||||
background: #07a583;
|
||||
padding:3px 15px;
|
||||
border: 1px dashed rgba(255, 255, 255, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
word-break: break-all;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
a{
|
||||
display: block;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
word-break: break-all;
|
||||
position: relative;
|
||||
padding-right: 32px;
|
||||
}
|
||||
img{
|
||||
margin-left: 5px;
|
||||
transition: .3s;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
}
|
||||
&:hover{
|
||||
box-shadow: 0px 0px 6px 1px rgba(31,120,49,0.98);
|
||||
border-color: #FFFFFF;
|
||||
img{
|
||||
right: -5px;
|
||||
}
|
||||
}
|
||||
&.unHover:hover{
|
||||
box-shadow: unset;
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.last_box{
|
||||
background-image: url('./img/zone1/last.png');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
.shandowTitle{
|
||||
font-family:Alimama ShuHeiTi;
|
||||
font-weight:700;
|
||||
color:#1f2329;
|
||||
font-size:22px;
|
||||
position: relative;
|
||||
width: 1200px;
|
||||
margin:0px auto;
|
||||
text-align: left;
|
||||
span{
|
||||
position: absolute;
|
||||
background:linear-gradient(180deg,#d8ddf0 0%,rgba(224, 229, 250, 0) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
top: -13px;
|
||||
left: 0px;
|
||||
}
|
||||
}
|
||||
.joinButton{
|
||||
width: 140px;
|
||||
height: 40px;
|
||||
line-height: 40px!important;
|
||||
color: #ffffff!important;
|
||||
background-color: #07a583!important;
|
||||
border-radius: 2px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
}
|
||||
.anchor_kxy{
|
||||
width: 200px;
|
||||
z-index: 1000;
|
||||
top: 50%;
|
||||
left: 200px;
|
||||
position: fixed;
|
||||
.ant-anchor-link{
|
||||
margin:15px 0px;
|
||||
text-align: left;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.ant-anchor-ink-ball{
|
||||
display: none;
|
||||
}
|
||||
.ant-anchor-link-title-active,.ant-anchor-link-active{
|
||||
color:#07a583;
|
||||
position: relative;
|
||||
}
|
||||
.ant-anchor-link-active::before{
|
||||
position: absolute;
|
||||
content: "";
|
||||
top:0px;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
border:none;
|
||||
left: -3px;
|
||||
background-color:#07a583;
|
||||
}
|
||||
}
|
||||
|
||||
.system_open{
|
||||
background:#f7f9fc;
|
||||
padding:80px 0px;
|
||||
&>div{
|
||||
width: 1200px;
|
||||
margin:0px auto;
|
||||
}
|
||||
.sys_box{
|
||||
align-items: flex-start;
|
||||
color: #1f2329;
|
||||
font-size: 17px;
|
||||
justify-content: space-evenly;
|
||||
&>div{
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
.sys_ul{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
li{
|
||||
width: 180px;
|
||||
height: 49px;
|
||||
background: #f6f7fa;
|
||||
border: 2px solid rgba(255, 255, 255, 0.45);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0px 0px 35px rgba(7, 70, 165, 0.11);
|
||||
color: #111111;
|
||||
font-size: 16px;
|
||||
line-height: 49px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media screen and (min-width: 1400px) {
|
||||
.anchor_kxy {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1500px) {
|
||||
.anchor_kxy {
|
||||
left: 100px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1600px) {
|
||||
.anchor_kxy {
|
||||
left: 150px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1700px) {
|
||||
.anchor_kxy {
|
||||
left: 80px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1800px) {
|
||||
.anchor_kxy {
|
||||
left: 100px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1900px) {
|
||||
.anchor_kxy {
|
||||
left: 190px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ function IssueCommentList(props){
|
|||
<div className='operationCommentBor'></div>
|
||||
<div className='flexCenter font-14' style={{width: '100%'}}>
|
||||
<div className='flexCenter opBox'>
|
||||
<span className='iconBackBox mr10'><i className={`iconfont font-12 ${journalsIcon[item.operate_category]}`}></i></span>
|
||||
<span className='iconBackBox mr10'><i className={`iconfont font-12 ${journalsIcon[item.operate_category] || "icon-xiugaibaobiaomoba"}`}></i></span>
|
||||
<div className='task-hide' style={{maxWidth: item.closeAndSpan && item.id === item.start? '550px' : '700px'}}>
|
||||
<Link to={`/${item.user.login}`}><img src={getImageUrl(item.user.image_url)} alt="" className='commentUserImg mr5'/></Link>
|
||||
<Link to={`/${item.user.login}`}>{item.user.name} </Link>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ function NewPanel(props,ref){
|
|||
},[title , desc , files])
|
||||
|
||||
function onContentChange(value){
|
||||
console.log("-----------------",value);
|
||||
setDescription(value);
|
||||
}
|
||||
function UploadFunc(f){
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ function Sign(props){
|
|||
}
|
||||
|
||||
function createSign(){
|
||||
setEditId(undefined);
|
||||
const c = Math.random().toString(16).substr(-6);
|
||||
c && setDefaultColor(`#${c}`);
|
||||
setEdit(true);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout';
|
||||
import { Dropdown , Menu , Divider , Spin, Button , Typography } from 'antd';
|
||||
import { Dropdown , Menu , Divider , Spin, Button, Tooltip } from 'antd';
|
||||
import { getImageUrl , turnbar , returnbar } from "educoder";
|
||||
import { Link } from 'react-router-dom';
|
||||
import { connect } from 'react-redux';
|
||||
|
|
@ -13,7 +12,7 @@ import axios from 'axios';
|
|||
import Path from './CoderDepotPath';
|
||||
import Catalogue from './CoderDepotCatalogue';
|
||||
import ReadMe from './CoderDepotReadme';
|
||||
import CoderRootFileDetail from './CoderRootFileDetail';
|
||||
// import CoderRootFileDetail from './CoderRootFileDetail';
|
||||
import './Index.scss';
|
||||
import Releases from '../Component/Releases';
|
||||
import Contributors from '../Component/Contributors';
|
||||
|
|
@ -24,13 +23,25 @@ import Nodata from '../Nodata';
|
|||
import Invite from './sub/Invite';
|
||||
import CheckProfile from '../Component/ProfileModal/Profile';
|
||||
import RenderHtml from '../../components/render-html';
|
||||
import Loadable from 'react-loadable';
|
||||
import Loading from '../../Loading';
|
||||
import ProjectPortrait from '../Component/projectPortrait';
|
||||
import imNoneImg from './img/importNone.png';
|
||||
import moment from 'moment';
|
||||
|
||||
const format = "YYYY-MM-DD HH:mm"
|
||||
const CoderRootFileDetail = Loadable({
|
||||
loader: () => import("./CoderRootFileDetail"),
|
||||
loading: Loading,
|
||||
});
|
||||
const mangementOperate =["Manager","Admin","Owner"]
|
||||
/**
|
||||
* projectDetail.type:0是托管项目,1是镜像项目,2是同步镜像项目(为2时不支持在线创建、在线上传、在线修改、在线删除、创建合并请求等功能)
|
||||
* project.open_portrait: 是否开启项目画像展示
|
||||
*/
|
||||
function CoderDepot(props){
|
||||
// const [ projectDetail , setProjectDetail ]= useState(undefined);
|
||||
let { platform , mirror_status , bannerList , projectDetail, projectEntries, projectReadMe } = props ;
|
||||
|
||||
let { platform , mirror_status , bannerList , projectDetail, projectEntries, projectReadMe, project } = props ;
|
||||
projectDetail = props.defaultDetail || projectDetail || {}
|
||||
|
||||
const [ inviteCode , setInviteCode ] = useState(projectDetail.invite_code || undefined);
|
||||
|
|
@ -40,7 +51,7 @@ function CoderDepot(props){
|
|||
const [ lastCommitAuthor,setLastCommitAuthor ] = useState((projectEntries.last_commit && projectEntries.last_commit.author) || undefined);
|
||||
const [ type ,setType ] = useState('dir');
|
||||
const [ hide , setHide ] = useState(true);
|
||||
const [ hideBtn , setHideBtn ] = useState(false);
|
||||
const [ hideBtn , setHideBtn ] = useState(true);
|
||||
const [ commitCount ,setCommitCount ] = useState(projectEntries.commits_count || 0);
|
||||
const [ dirInfo ,setDirInfo ] = useState(projectEntries.entries || undefined);//文件夹目录列表
|
||||
const [ fileInfo ,setFileInfo ] = useState(undefined);//文件内容信息
|
||||
|
|
@ -55,7 +66,7 @@ function CoderDepot(props){
|
|||
const [ website , setWebsite ] = useState(projectDetail.website ||undefined);
|
||||
const [ lesson_url , setLessonUrl ] = useState(projectDetail.lesson_url || undefined);
|
||||
const [ topics, setTopics] = useState(projectDetail.topics || undefined);
|
||||
const [ readme , setReadme ] = useState(projectReadMe || undefined);
|
||||
const [ readme , setReadme ] = useState((projectReadMe && JSON.parse(decodeURIComponent(projectReadMe))) || undefined);
|
||||
const [ defaultBranch , setDefaultBranch ] = useState(projectDetail.default_branch || undefined);
|
||||
const [ editReadme , setEditReadme ] = useState(false);
|
||||
const [ pullsFlag , setPullsFlag ] = useState(true);
|
||||
|
|
@ -222,7 +233,7 @@ function CoderDepot(props){
|
|||
let ele = document.getElementById("ptxt");
|
||||
if(ele){
|
||||
let h = ele.offsetHeight;
|
||||
if( h > 36 ) setHideBtn(true);
|
||||
if( h <= 36 ) setHideBtn(false);
|
||||
}
|
||||
}
|
||||
},[projectDetail,lastCommit])
|
||||
|
|
@ -402,7 +413,7 @@ function CoderDepot(props){
|
|||
const baseOperate = projectDetail && projectDetail.permission && projectDetail.permission !=="Reporter" && projectDetail.type !==2 && pullsFlag && props.platform;
|
||||
const fileOperate = type === "dir" && projectDetail && projectDetail.type !==2 && ((projectDetail.permission && projectDetail.permission !=="Reporter") || (current_user && current_user.admin));
|
||||
return(
|
||||
<WhiteBack>
|
||||
<div className='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}>
|
||||
{
|
||||
|
|
@ -425,13 +436,30 @@ function CoderDepot(props){
|
|||
</React.Fragment>
|
||||
}
|
||||
<div style={{minHeight:"500px"}}>
|
||||
{
|
||||
mirror_status === 2 &&
|
||||
<div className='importFailTip'>
|
||||
<img src={imNoneImg} alt="" width={290}/>
|
||||
{
|
||||
projectDetail.permission && mangementOperate.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 className='font-17 weight500'>导入项目失败,请联系管理员重新导入!</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
{
|
||||
projectDetail &&
|
||||
<Box className="Panels">
|
||||
<LongWidth>
|
||||
projectDetail && mirror_status === 0 &&
|
||||
<div className="Panels Box">
|
||||
<div className="LongWidth">
|
||||
<div className="panelmenu">
|
||||
<FlexAJ>
|
||||
<AlignCenter>
|
||||
<div className="FlexAJ">
|
||||
<div className="AlignCenter">
|
||||
<div className="mr30">
|
||||
{
|
||||
props && (props.platform && mirror_status ===0) ?
|
||||
|
|
@ -459,7 +487,7 @@ function CoderDepot(props){
|
|||
/>
|
||||
:
|
||||
<React.Fragment>
|
||||
<AlignCenter className="mr20">
|
||||
<div className="mr20 AlignCenter">
|
||||
{
|
||||
props.platform ?
|
||||
<Link to={`/${owner}/${projectsId}/branches`} className="iconBtn">
|
||||
|
|
@ -474,8 +502,8 @@ function CoderDepot(props){
|
|||
<span className="ml3">{projectDetail && projectDetail.branches_count}</span>
|
||||
</span>
|
||||
}
|
||||
</AlignCenter>
|
||||
<AlignCenter className="mr20">
|
||||
</div>
|
||||
<div className="mr20 AlignCenter">
|
||||
{
|
||||
props.platform ?
|
||||
<Link to={`/${owner}/${projectsId}/tags`} className="iconBtn">
|
||||
|
|
@ -489,11 +517,11 @@ function CoderDepot(props){
|
|||
<span className="ml3">{projectDetail && projectDetail.tags_count}</span>
|
||||
</span>
|
||||
}
|
||||
</AlignCenter>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
}
|
||||
</AlignCenter>
|
||||
<AlignCenter className="depotBtn">
|
||||
</div>
|
||||
<div className="depotBtn AlignCenter">
|
||||
<div className="addOptionBtn">
|
||||
{
|
||||
baseOperate &&
|
||||
|
|
@ -525,8 +553,8 @@ function CoderDepot(props){
|
|||
<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>
|
||||
</Dropdown>
|
||||
</AlignCenter>
|
||||
</FlexAJ>
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
(dirInfo && dirInfo.length>0) || fileInfo ?
|
||||
<div className="listtable">
|
||||
|
|
@ -543,9 +571,9 @@ function CoderDepot(props){
|
|||
<pre id="ptxt"><Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(lastCommit.sha)}`}><RenderHtml value={lastCommit.message}/></Link></pre>
|
||||
</div>
|
||||
}
|
||||
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
|
||||
{ hideBtn && __CLIENT__ && <div className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></div> }
|
||||
|
||||
<span className="ml20 color-grey-6 font-12 mt3">{lastCommit.time_from_now}</span>
|
||||
<Tooltip title={lastCommit.committer && moment(lastCommit.committer.date).format(format)}><span className="ml20 color-grey-6 font-12 mt3">{lastCommit.time_from_now}</span></Tooltip>
|
||||
{
|
||||
commitCount ?
|
||||
<Link to={`/${owner}/${projectsId}/commits/branch/${turnbar(branchName || defaultBranch)}`} className="ml20 color-grey-3"style={{height:"28px",lineHeight:"28px"}}>
|
||||
|
|
@ -571,7 +599,7 @@ function CoderDepot(props){
|
|||
})
|
||||
}
|
||||
{
|
||||
fileInfo &&
|
||||
fileInfo && __CLIENT__ &&
|
||||
<CoderRootFileDetail
|
||||
{...props}
|
||||
detail={fileInfo}
|
||||
|
|
@ -594,18 +622,18 @@ function CoderDepot(props){
|
|||
{/* readme文件显示(显示文件详情时不显示readme文件) */}
|
||||
{ (readme && readme.replace_content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
|
||||
</div>
|
||||
</LongWidth>
|
||||
</div>
|
||||
{
|
||||
(!(treeValuePath && treeValuePath.length > 0) && !fileInfo ) &&
|
||||
<ShortWidth>
|
||||
<Gap style={{paddingLeft:"30px"}}>
|
||||
<div className="ShortWidth">
|
||||
<div className="Gap" style={{paddingLeft:"30px"}}>
|
||||
<div className="panelmenu">
|
||||
<FlexAJ className="font-18 color-ooo mb20" style={{lineHeight:"28px"}}>关于
|
||||
<div className="font-18 color-ooo mb20 FlexAJ" style={{lineHeight:"28px"}}>关于
|
||||
{
|
||||
projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner" || projectDetail.permission==="Manager") &&
|
||||
<i onClick={()=>setOpenModal(true)} className="iconfont icon-a-shezhi color-grey-9 font-15 pointer"></i>
|
||||
}
|
||||
</FlexAJ>
|
||||
</div>
|
||||
{desc && <p className="font-14 color-grey-3 mb15 task-hide-2" style={{lineHeight:"24px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}} title={desc}>{desc}</p>}
|
||||
{/* 项目标签 */}
|
||||
{topics && <div className='projectHomeTopics'>
|
||||
|
|
@ -665,16 +693,18 @@ function CoderDepot(props){
|
|||
}
|
||||
{/* 贡献者 */}
|
||||
{mirror_status ===0 && <Contributors owner={owner} projectsId={projectsId} /> }
|
||||
{/* 项目画像: 导入/fork项目不展示, open_portrait后台配置是否开启仓库 */}
|
||||
{__CLIENT__ && projectDetail && !projectDetail.type && !projectDetail.forked_from_project_id && project && project.open_portrait && <ProjectPortrait owner={owner} projectsId={projectsId}/>}
|
||||
{/* 语言 */}
|
||||
{ mirror_status ===0 && <LanguagePower owner={owner} projectsId={projectsId}/> }
|
||||
</Gap>
|
||||
</ShortWidth>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</Box>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</Spin>
|
||||
</WhiteBack>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React , { useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import {Tooltip} from 'antd';
|
||||
import {getEmoji} from './emoji';
|
||||
const typeIco = {
|
||||
"submodule":"icon-file-submodule font-17",
|
||||
|
|
@ -53,11 +54,13 @@ function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId , platform
|
|||
}
|
||||
</span>
|
||||
<span title="init project">
|
||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.commit && item.commit.sha}`)}`} title={item.commit && item.commit.message}>
|
||||
{getEmoji(getMessage(item.commit && item.commit.message.split('\n')[0]))}
|
||||
</Link>
|
||||
|
||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.commit && item.commit.sha}`)}`} title={item.commit && item.commit.message}>
|
||||
{getEmoji(getMessage(item.commit && item.commit.message.split('\n')[0]))}
|
||||
</Link>
|
||||
|
||||
</span>
|
||||
<span title={item.commit && item.commit.created_at}>{item.commit && item.commit.time_from_now}</span>
|
||||
<Tooltip title={item.commit && item.commit.created_at} placement="right"><span>{item.commit && item.commit.time_from_now}</span></Tooltip>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ function CoderDepotReadme({ operate , history , readme , ChangeFile }){
|
|||
<div className="commonBox readBox" id="readme">
|
||||
<Anchor offsetTop={58}>
|
||||
<div className="commonBox-title boxTitle">
|
||||
<AlignCenter>
|
||||
<div className="AlignCenter">
|
||||
<Dropdown overlay={menu()} trigger={['hover']} overlayClassName="menuslist">
|
||||
<span className="catelogue">
|
||||
<i className="iconfont icon-muluicon font-12 mr5"></i>
|
||||
|
|
@ -53,7 +53,7 @@ function CoderDepotReadme({ operate , history , readme , ChangeFile }){
|
|||
|
||||
<span className="commonBox-title-read"><a href="#readme ">{readme.name}</a></span>
|
||||
|
||||
</AlignCenter>
|
||||
</div>
|
||||
{
|
||||
operate ?
|
||||
<a className="ml20 pull-right" onClick={() =>ChangeFile(readme && readme.path, false)}>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import ReadmeCatelogue from "./sub/ReadmeCatelogue";
|
|||
import { Base64 } from "js-base64";
|
||||
import ReplaceModal from "./Modal/ReplaceModal";
|
||||
import {returnbar , turnbar} from 'educoder';
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
|
||||
const $ = window.$;
|
||||
function bytesToSize(bytes) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Route , Switch } from 'react-router-dom';
|
|||
import Loadable from 'react-loadable';
|
||||
import Loading from '../../Loading';
|
||||
import './Index.scss';
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
|
||||
const FileNew = Loadable({
|
||||
loader: () => import('../Newfile/Index'),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Spin, Tooltip } from 'antd';
|
||||
import { Spin, Tooltip , Button } from 'antd';
|
||||
import { Link, Route, Switch } from 'react-router-dom';
|
||||
import { withRouter } from "react-router";
|
||||
import { connect } from 'react-redux';
|
||||
|
|
@ -15,6 +15,9 @@ import types from '../../redux/actions/actionTypes'
|
|||
import { getProjectFunc, getProjectDetailFunc } from '../../services/project'
|
||||
import '../css/index.scss'
|
||||
import './list.scss';
|
||||
import '../../modules/courses/css/Courses.css'
|
||||
import { ImageLayerOfCommentHOC } from "../../modules/page/layers/ImageLayerOfCommentHOC";
|
||||
import { unInstallMarketBot } from "../../softbot/api";
|
||||
|
||||
|
||||
import Loadable from 'react-loadable';
|
||||
|
|
@ -129,11 +132,11 @@ const DevIndex = Loadable({
|
|||
loading: Loading,
|
||||
});
|
||||
const Wiki = Loadable({
|
||||
loader: () => import('../Wiki/Index'),
|
||||
loader: () => import('../Wiki/page/index'),
|
||||
loading: Loading,
|
||||
});
|
||||
const WikiEdit = Loadable({
|
||||
loader: () => import('../Wiki/EditWiki'),
|
||||
loader: () => import('../Wiki/page/edit'),
|
||||
loading: Loading,
|
||||
});
|
||||
const Invite = Loadable({
|
||||
|
|
@ -206,15 +209,14 @@ class Detail extends Component {
|
|||
defaultBranch: undefined,
|
||||
|
||||
// 非本平台项目
|
||||
platform: false,
|
||||
mirror_status:2,
|
||||
platform: true,
|
||||
mirror_status:0,
|
||||
bannerList: props.projectMenu || []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
componentDidMount = () => {
|
||||
// this.getProject();
|
||||
componentDidMount=()=>{
|
||||
let history = this.props.location;
|
||||
this.clearIssueCookies(history);
|
||||
if (this.props.clearProject) {
|
||||
|
|
@ -225,7 +227,8 @@ class Detail extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
componentDidUpdate = async (prevState) => {
|
||||
|
||||
componentDidUpdate = async (prevState) => {
|
||||
let prevParam = prevState.match.params;
|
||||
let propsParam = this.props.match.params;
|
||||
if (prevState && this.props && (prevParam.projectsId !== propsParam.projectsId || prevParam.owner !== propsParam.owner)) {
|
||||
|
|
@ -240,7 +243,7 @@ class Detail extends Component {
|
|||
// 非issue链接地址清除cookie states,具体保存和操作在order.js页面
|
||||
this.clearIssueCookies(history);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
clearIssueCookies = (history) => {
|
||||
const { pathname } = history;
|
||||
|
|
@ -252,12 +255,10 @@ class Detail extends Component {
|
|||
}
|
||||
}
|
||||
async componentWillMount() {
|
||||
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
|
||||
if (!this.props.projectBase) {
|
||||
const data = await getProjectFunc(owner, projectsId);
|
||||
if (data.data) {
|
||||
if (data && data.data) {
|
||||
this.getProject(data.data)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -277,33 +278,18 @@ class Detail extends Component {
|
|||
})
|
||||
if (data.type !== 0 && data.mirror_status === 1) {
|
||||
console.log("--------start channel --------");
|
||||
// 是镜像项目,且未完成迁移
|
||||
this.canvasChannel();
|
||||
if (num) {
|
||||
this.setState({
|
||||
secondSync: true,
|
||||
firstSync: false
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
firstSync: true,
|
||||
secondSync: false
|
||||
})
|
||||
}
|
||||
this.setState({
|
||||
firstSync: true,
|
||||
secondSync: false,
|
||||
mirror_status:1
|
||||
})
|
||||
} else if (data.mirror_status === 2) {
|
||||
this.setState({
|
||||
mirror_status:2,
|
||||
firstSync: false
|
||||
})
|
||||
this.deleteProjectBack();
|
||||
// 是镜像项目,且未完成迁移
|
||||
this.canvasChannel();
|
||||
} else {
|
||||
this.setState({
|
||||
firstSync: false,
|
||||
secondSync: false,
|
||||
mirror_status:0
|
||||
mirror_status:data.mirror_status || 0
|
||||
})
|
||||
this.getBanner(this.props.projectMenu)
|
||||
let projectdata
|
||||
|
|
@ -311,7 +297,7 @@ class Detail extends Component {
|
|||
projectdata = this.props.defaultDetail
|
||||
} else {
|
||||
const res = await getProjectDetailFunc(owner, projectsId, !window.location.host);
|
||||
if (res.status === 200) {
|
||||
if (res && res.status === 200) {
|
||||
projectdata = res.data
|
||||
}
|
||||
}
|
||||
|
|
@ -346,24 +332,29 @@ class Detail extends Component {
|
|||
disconnected: () => {
|
||||
console.log("###### cannot connected! ######");
|
||||
},
|
||||
received: data => {
|
||||
received: async data => {
|
||||
console.log(`###### ---received data--- ######`);
|
||||
if (data) {
|
||||
console.log("start ----",data)
|
||||
if (deleteFlag) {
|
||||
this.setState({
|
||||
firstSync: false,
|
||||
mirror_status:data.project && data.project.mirror_status,
|
||||
secondSync: false
|
||||
});
|
||||
this.props.showNotification("镜像同步成功!");
|
||||
window.location.reload();
|
||||
} else {
|
||||
if (data.project && data.project.mirror_status === 2) {
|
||||
this.deleteProjectBack();
|
||||
}
|
||||
// else {
|
||||
if (data.status === -1) {
|
||||
// this.deleteProjectBack();
|
||||
// const projectdata = await getProjectDetailFunc(owner, projectsId, !window.location.host).data;
|
||||
// this.getDetail(projectdata)
|
||||
// this.getBanner();
|
||||
this.toMirrorFunc();
|
||||
}
|
||||
this.getDetail();
|
||||
this.getBanner();
|
||||
}
|
||||
this.setState({
|
||||
firstSync: false,
|
||||
mirror_status:data.project && data.project.mirror_status,
|
||||
secondSync: false
|
||||
});
|
||||
// }
|
||||
// this.reloadDetail();
|
||||
cable.subscriptions.consumer.disconnect();
|
||||
}
|
||||
},
|
||||
|
|
@ -384,24 +375,32 @@ 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;
|
||||
}
|
||||
toMirrorFunc=()=>{
|
||||
let hash = '/projects/mirror/new';
|
||||
this.props.history.push({
|
||||
pathname: hash,
|
||||
mirror_status: 2
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 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 = async (data) => {
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
if (!data) {
|
||||
|
|
@ -440,7 +439,7 @@ class Detail extends Component {
|
|||
defaultBranch: data.default_branch
|
||||
});
|
||||
// seo优化设置
|
||||
let keyWords=`${owner},${projectsId}${ data.topics.length > 0 && ','}${ data.topics.length > 0 && data.topics.map(item => item.name).join(',') }`;
|
||||
let keyWords=`${owner},${projectsId}${ data.topics && data.topics.length > 0 && ','}${ data.topics && data.topics.length > 0 && data.topics.map(item => item.name).join(',') }`;
|
||||
let title= `${owner}/${projectsId}${data.description?':'+data.description:''}`;
|
||||
setSeoMeta(keyWords,title,data.description || '',`/${owner}/${projectsId}`,owner,projectsId);
|
||||
}
|
||||
|
|
@ -450,19 +449,28 @@ class Detail extends Component {
|
|||
// 获取动态导航栏菜单
|
||||
async getBanner(data) {
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
if (!data) {
|
||||
const url = `/${owner}/${projectsId}/menu_list.json`;
|
||||
const res = await axios.get(url)
|
||||
if (res.data) {
|
||||
data = res.data
|
||||
const url = `/${owner}/${projectsId}/menu_list.json`;
|
||||
axios.get(url).then(res=>{
|
||||
if(res && res.data){
|
||||
this.setState({
|
||||
bannerList: res.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (data) {
|
||||
this.setState({
|
||||
bannerList: data
|
||||
})
|
||||
}
|
||||
})
|
||||
// if (!data) {
|
||||
// const url = `/${owner}/${projectsId}/menu_list.json`;
|
||||
// axios.get(url).then(res=>{
|
||||
// if(res && res.data){
|
||||
// this.setState({
|
||||
// bannerList: res.data
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// }else{
|
||||
// this.setState({
|
||||
// bannerList: data
|
||||
// })
|
||||
// }
|
||||
}
|
||||
|
||||
// 关注和取消关注
|
||||
|
|
@ -534,12 +542,14 @@ class Detail extends Component {
|
|||
const url = `/${owner}/${projectsId}/forks.json`;
|
||||
axios.post(url).then(result => {
|
||||
if (result && result.data.status === 0) {
|
||||
if (result.data.message === "fork失败,你已拥有了这个项目") {
|
||||
this.props.showNotification(result.data.message);
|
||||
if (result.data.message && result.data.message.indexOf("fork失败")>-1) {
|
||||
// fork失败,已经fork过,跳转到fork的仓库
|
||||
this.props.history.push(`/${current_user && current_user.login}/${projectsId}`);
|
||||
return;
|
||||
}
|
||||
this.props.history.push(`/${current_user && current_user.login}/${result.data.identifier}`);
|
||||
this.props.showNotification(result.data.message);
|
||||
|
||||
this.props.showNpsModal("indexProject", 3);
|
||||
}
|
||||
this.setState({
|
||||
|
|
@ -590,11 +600,29 @@ 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,
|
||||
isManager, watched, praised,
|
||||
forked_count, firstSync, secondSync, watched, praised,
|
||||
project, open_devops, platform, defaultBranch, bannerList, forkSpin , mirror_status } = this.state;
|
||||
const url = this.props.history.location.pathname;
|
||||
const urlArr = url.split("/");
|
||||
|
|
@ -616,9 +644,9 @@ class Detail extends Component {
|
|||
<div>
|
||||
<div className="detailHeader-wrapper">
|
||||
<div className="normal">
|
||||
<AlignTop style={{ padding: "18px 0px 10px", justifyContent: "space-between" }}>
|
||||
<div className="AlignTop" style={{ padding: "18px 0px 10px", justifyContent: "space-between" }}>
|
||||
<div>
|
||||
<AlignTop>
|
||||
<div className="AlignTop">
|
||||
<div className="projectallName">
|
||||
{project && project.author &&
|
||||
<Link to={`/${project.author.login}`}>{project.author.name}</Link>
|
||||
|
|
@ -628,7 +656,7 @@ class Detail extends Component {
|
|||
</div>
|
||||
{projectDetail && projectDetail.private && <span className="privateTag mt6">私有</span>}
|
||||
{!platform && <span className="privateTag red mt6">只读</span>}
|
||||
</AlignTop>
|
||||
</div>
|
||||
<div className="mt8">
|
||||
{
|
||||
projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
|
||||
|
|
@ -696,7 +724,7 @@ class Detail extends Component {
|
|||
</span>
|
||||
}
|
||||
</div>
|
||||
</AlignTop>
|
||||
</div>
|
||||
{/* <div className="mt6" style={{minHeight:"20px"}}>
|
||||
{
|
||||
projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ?
|
||||
|
|
@ -733,10 +761,14 @@ 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">
|
||||
<Switch {...this.props}>
|
||||
{/* mirror_status = 1的情况不显示项目详情子模块 */}
|
||||
{!firstSync && <Switch {...this.props}>
|
||||
{/* 服务 */}
|
||||
<Route path="/:owner/:projectsId/service"
|
||||
render={
|
||||
|
|
@ -774,15 +806,15 @@ class Detail extends Component {
|
|||
}
|
||||
></Route>
|
||||
{/* wiki编辑文件 */}
|
||||
<Route path="/:owner/:projectsId/wiki/:wikiName/:key/edit"
|
||||
<Route path="/:owner/:projectsId/wiki/edit"
|
||||
render={
|
||||
() => (<WikiEdit {...this.props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
{/* wiki具体某一个地址 */}
|
||||
<Route path="/:owner/:projectsId/wiki/:wikiName/:key"
|
||||
{/* wiki复制文件 */}
|
||||
<Route path="/:owner/:projectsId/wiki/copy"
|
||||
render={
|
||||
(props) => (<Wiki {...this.props} {...props} {...this.state} {...common} />)
|
||||
() => (<WikiEdit {...this.props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
{/* wiki */}
|
||||
|
|
@ -930,7 +962,7 @@ class Detail extends Component {
|
|||
|
||||
<Route path="/:owner/:projectsId/:subIndex"
|
||||
render={
|
||||
(props) => (<CoderRootIndex {...this.props} {...props} {...this.state} {...common} />)
|
||||
(props) => ( __CLIENT__ && <CoderRootIndex {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/:owner/:projectsId"
|
||||
|
|
@ -938,7 +970,7 @@ class Detail extends Component {
|
|||
(props) => <CoderDepot {...this.props} {...props} {...this.state} {...common} mirror_status={mirror_status}/>
|
||||
}
|
||||
></Route>
|
||||
</Switch>
|
||||
</Switch>}
|
||||
</Spin>
|
||||
</div>
|
||||
)
|
||||
|
|
@ -964,14 +996,14 @@ const mapDispatchToProps = (dispatch) => ({
|
|||
|
||||
Detail.preFetch = ({ store, match, query }) => {
|
||||
return new Promise(async function(resolve, reject) {
|
||||
let { dispatch, getState } = store;
|
||||
let { dispatch } = store;
|
||||
// const { owner,projectsId } = match.params
|
||||
const detail = await dispatch(setProjectDetail(match.params))
|
||||
const promises = [
|
||||
dispatch(setProjectDetail(match.params)),
|
||||
dispatch(setProject(match.params)),
|
||||
dispatch(setProjectEntries({...match.params, branch: ''})),
|
||||
dispatch(setProjectEntries({...match.params, branch: match.params.branchName ? match.params.branchName : detail.default_branch})),
|
||||
dispatch(setProjectMenuList(match.params)),
|
||||
dispatch(setProjectReadMe({...match.params, branch: ''}))
|
||||
dispatch(setProjectReadMe({...match.params, branch: match.params.branchName ? match.params.branchName : detail.default_branch}))
|
||||
];
|
||||
const data = await Promise.all(promises);
|
||||
resolve({
|
||||
|
|
@ -980,7 +1012,13 @@ Detail.preFetch = ({ store, match, query }) => {
|
|||
});
|
||||
};
|
||||
|
||||
export default withRouter(connect(
|
||||
export default __CLIENT__ ? withRouter(connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ImageLayerOfCommentHOC({
|
||||
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
|
||||
parentSelector: ".newContainer",
|
||||
})(Detail))) : withRouter(connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Detail));
|
||||
|
|
@ -553,8 +553,28 @@
|
|||
height: 140px!important;
|
||||
}
|
||||
.hovergrey:hover{
|
||||
border-color: #afb7c2;
|
||||
color:#4c5b76;
|
||||
background-color: rgba(175, 183, 194, 0.16);
|
||||
|
||||
border-color: #afb7c2!important;
|
||||
color:#4c5b76!important;
|
||||
background-color: rgba(175, 183, 194, 0.16)!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;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,16 +7,45 @@ import '../css/index.scss';
|
|||
import Nodata from '../Nodata';
|
||||
import './list.scss';
|
||||
import './Index.scss';
|
||||
import axios from 'axios';
|
||||
|
||||
class IndexItem extends Component {
|
||||
|
||||
TurnToDetail = (login, url) => {
|
||||
this.props.history.push({
|
||||
pathname: url,
|
||||
state: login
|
||||
})
|
||||
}
|
||||
|
||||
// 置顶与取消置顶
|
||||
setTop =(id)=>{
|
||||
const { current_user , InitFunc } = this.props;
|
||||
const url = `/v1/${current_user && current_user.login}/home_top_settings`;
|
||||
axios.post(url,{
|
||||
top_type:"Project",top_id:id
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
this.props.showNotification("置顶成功!");
|
||||
InitFunc && InitFunc();
|
||||
}
|
||||
})
|
||||
}
|
||||
unsetTop=(id)=>{
|
||||
const { current_user , InitFunc } = this.props;
|
||||
const url =`/v1/${current_user && current_user.login}/home_top_settings/cancel`;
|
||||
axios.delete(url,{
|
||||
params:{top_type:"Project",top_id:id}
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
this.props.showNotification("已成功取消置顶!");
|
||||
InitFunc && InitFunc();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { projects } = this.props;
|
||||
const { projects , isShowTop , isShowTopTag } = this.props;
|
||||
return (
|
||||
<div className="project-list minH-670" style={{padding:"0px 20px"}}>
|
||||
{ projects && projects.length > 0 ? projects.map((item, key) => {
|
||||
|
|
@ -24,20 +53,23 @@ class IndexItem extends Component {
|
|||
<div className="p-r-Item" key={key}>
|
||||
{
|
||||
item.platform === "educoder" ?
|
||||
<a href="javascript:void(0)" style={{cursor:"default"}} className="show-user-link">
|
||||
<a href={`/${item.author && item.author.login}`} style={{cursor:"default"}} className="show-user-link">
|
||||
<img className="p-r-photo" alt="" src={item.author && item.author.image_url} ></img>
|
||||
</a>
|
||||
:
|
||||
<a href="javascript:void(0)" onClick={() => { window.location.href = `/${item.author && item.author.login}/${item.identifier}` }} className="show-user-link">
|
||||
<a href={`/${item.author && item.author.login}/${item.identifier}`} className="show-user-link">
|
||||
<img className="p-r-photo" alt="" src={getImageUrl(`/${item.author && item.author.image_url}`)} ></img>
|
||||
</a>
|
||||
}
|
||||
<div className="p-r-Infos">
|
||||
<div className="p-r-name">
|
||||
<AlignCenter>
|
||||
<a href="javascript:void(0)" onClick={() => { window.location.href = `/${item.author && item.author.login}/${item.identifier}` }} title={`${item.author.name}/${item.name}`} className="color-grey-3 font-18 task-hide " style={{maxWidth: 470 }}>
|
||||
<a href={`/${item.author && item.author.login}/${item.identifier}`} title={`${item.author.name}/${item.name}`} className="color-grey-3 font-18 task-hide " style={{maxWidth: 470 }}>
|
||||
{item.author.name}/{item.name}
|
||||
</a>
|
||||
{
|
||||
isShowTopTag && item.is_home_top && <span className="topTag">置顶</span>
|
||||
}
|
||||
{ !item.is_public && <span className="privateTag">私有</span> }
|
||||
{
|
||||
item.forked_from_project_id ?
|
||||
|
|
@ -68,20 +100,26 @@ class IndexItem extends Component {
|
|||
}
|
||||
</span>
|
||||
</div>
|
||||
<p className="break_word task-hide-2 mt10" style={{ maxHeight: "44px",lineHeight:"22px" }}>{item.description}</p>
|
||||
{item.description && <p className="break_word task-hide-2 mb10" style={{ maxHeight: "44px",lineHeight:"22px" }}>{item.description}</p> }
|
||||
{/* 项目标签 */}
|
||||
{item.topics && <div className='projectHomeTopics myProList'>
|
||||
{item.topics.map(topic=><Link to={`/explore/topic/${topic.id}/${encodeURIComponent(topic.name)}`} className='proHomeTopic mr15 font-13 task-hide'>{topic.name}</Link>)}
|
||||
</div>}
|
||||
<div className="p-r-about">
|
||||
<span className="p-r-detail">
|
||||
{item.last_update_time ? <span><label>更新于</label>{item.time_ago}</span> : ""}
|
||||
{item.last_update_time ? <Tooltip placement='bottom' title={item.full_last_update_time && moment(item.full_last_update_time).format("YYYY-MM-DD HH:mm")}><span><label>更新于</label>{item.time_ago}</span></Tooltip> : ""}
|
||||
{item.language && item.language.id ? <span className="color-grey-3">{item.language.name}</span> : ""}
|
||||
</span>
|
||||
{/* <span>
|
||||
<Button type="primary" size="small">置顶</Button>
|
||||
<Button size="small" style={{height:"26px",lineHeight:"24px"}} className="hovergrey">取消置顶</Button>
|
||||
</span> */}
|
||||
{
|
||||
isShowTop &&
|
||||
<span className="setTopSpan">
|
||||
{item.is_home_top ?
|
||||
<Button size="small" style={{height:"26px",lineHeight:"24px"}} onClick={()=>{this.unsetTop(item.id)}} className="hovergrey font-13">取消置顶</Button>
|
||||
:
|
||||
<Button type="primary" size="small" onClick={()=>{this.setTop(item.id)}} className='font-13'>置顶</Button>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 41 KiB |
|
|
@ -76,7 +76,17 @@
|
|||
color: #fff!important;
|
||||
}
|
||||
|
||||
|
||||
.topTag{
|
||||
width: 40px;
|
||||
height: 18px;
|
||||
text-align: center;
|
||||
line-height: 17px;
|
||||
border: 1px solid #e94000;
|
||||
font-size: 12px;
|
||||
color: #e94000;
|
||||
border-radius: 12px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
/* 列表 */
|
||||
.project-list{
|
||||
padding:0px 30px;
|
||||
|
|
@ -92,6 +102,13 @@
|
|||
border-bottom:1px solid rgba(238,238,238,1);
|
||||
padding:22px 0px;
|
||||
justify-content: flex-start;
|
||||
.setTopSpan{
|
||||
opacity: 0;
|
||||
transition: 0.2s;
|
||||
}
|
||||
}
|
||||
.p-r-Item:hover .setTopSpan{
|
||||
opacity: 1;
|
||||
}
|
||||
.boxShandow{
|
||||
box-shadow:0px 2px 20px 10px rgba(0,0,0,0.03);
|
||||
|
|
@ -211,6 +228,7 @@
|
|||
}
|
||||
.spincontent{
|
||||
height:400px;
|
||||
flex-direction: column;
|
||||
}
|
||||
.spinstyle .ant-spin-text{
|
||||
margin-top:30px;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
import './Index.scss';
|
||||
import SubBanner from './SubBanner';
|
||||
import SubUnitBanner from './SubUnitBanner';
|
||||
import Icon from '../img/index/icon.png';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Spin , Input } from 'antd';
|
||||
import { Spin , Input, Tooltip } from 'antd';
|
||||
import SubList from './SubList';
|
||||
import more from '../img/index/more.png';
|
||||
import axios from 'axios';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import Nodata from '../../Nodata';
|
||||
import moment from 'moment';
|
||||
|
||||
const { Search } = Input;
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ function Index() {
|
|||
}
|
||||
<div className="itemTitle">
|
||||
<div className="item-title-infos">
|
||||
<a href="javascript:void(0)" onClick={() => { window.location.href = `/${i.author && i.author.login}/${i.identifier}` }} className="infotitle task-hide">{i.author && i.author.name}/{i.name}</a>
|
||||
<a href={ `/${i.author && i.author.login}/${i.identifier}` } className="infotitle task-hide">{i.author && i.author.name}/{i.name}</a>
|
||||
{i.praises_count > 0 ? <span><i className="iconfont icon-xingzhuang mr3 font-14"></i>{i.praises_count}</span> :"" }
|
||||
{i.forked_count > 0 ? <span><i className="iconfont icon-yifuke_icon mr3 font-14"></i>{i.forked_count}</span>:""}
|
||||
</div>
|
||||
|
|
@ -128,7 +128,7 @@ function Index() {
|
|||
<div className="item-data">
|
||||
{i.category && i.category.id ? <span className="category">{i.category.name}</span> :"" }
|
||||
{i.language && i.language.id ? <span className={`language mr30 ${i.category && i.category.id ? 'hasCate' : ''}`}>{i.language.name}</span> :""}
|
||||
<span style={{lineHeight:"15px",display:"flex"}}><i className="iconfont icon-shijian font-15 mr5"></i>更新于{i.time_ago}</span>
|
||||
<span style={{lineHeight:"15px",display:"flex"}}><Tooltip placement='bottom' title={i.full_last_update_time && moment(i.full_last_update_time).format("YYYY-MM-DD HH:mm")}><i className="iconfont icon-shijian font-15 mr5"></i>更新于{i.time_ago}</Tooltip></span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import datasetImg from '../img/dataset.jpg';
|
|||
import axios from 'axios';
|
||||
|
||||
function DetailBanner({ history,list , owner , projectsId ,showNotification , url , pathname , state , urlFlag , projectDetail , platform ,open_devops ,current_user, showNpsModal }){
|
||||
const [ menuName , setMenuName ] = useState(undefined);
|
||||
const [ menuName , setMenuName ] = useState(list);
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
|
||||
useEffect(()=>{
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ function Tags(props) {
|
|||
}
|
||||
</Tooltip>
|
||||
}
|
||||
<span>最后一次提交于{item.time_ago}</span>
|
||||
<Tooltip placement="right" title={moment(item.created_time).format("YYYY-MM-DD HH:mm")}><span>最后一次提交于{item.time_ago}</span></Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,10 +6,13 @@ import { getImageUrl , turnbar } from 'educoder';
|
|||
import { Button, Dropdown , Input, Menu , message, Modal, Select, Spin, Table, Tooltip , Radio , Popover } from 'antd';
|
||||
import Modals from '../../Component/PublicModal/Index';
|
||||
import './Index.scss';
|
||||
import moment from 'moment';
|
||||
|
||||
import Tree from '../img/tree.png';
|
||||
import Axios from 'axios';
|
||||
|
||||
const format = "YYYY-MM-DD HH:mm";
|
||||
|
||||
function Index(props) {
|
||||
const [ reload, setReload] = useState(undefined);
|
||||
const [ list , setList ] = useState([]);
|
||||
|
|
@ -87,7 +90,7 @@ function Index(props) {
|
|||
<span style={{fontWeight:"500"}}>{txt && txt.committer && txt.committer.name}</span>
|
||||
</React.Fragment>
|
||||
}
|
||||
<span className="color-grey-3">更新于{txt && txt.time_ago}</span>
|
||||
<Tooltip title={item && item.commit_time && moment(item.commit_time).format(format)} placement='right'><span className="color-grey-3">更新于{txt && txt.time_ago}</span></Tooltip>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)}`;
|
||||
|
|
|
|||
|
|
@ -133,8 +133,7 @@ function Files({ data,history,owner,projectsId , parentsSha }){
|
|||
</span>
|
||||
<div style={{display:"flex"}}>
|
||||
<span className="linetype">{item.type===2 ? "+" : item.type===3 ? "-" :""}</span>
|
||||
<div dangerouslySetInnerHTML={{__html:(item.type===3 || item.type===2) ? subStrContent(item.content) : item.content}}></div>
|
||||
{/* <div><span style={{whiteSpace:"pre-wrap"}}>{(item.type===3 || item.type===2) ? subStrContent(item.content) : item.content}</span></div> */}
|
||||
<div><span style={{whiteSpace:"pre-wrap"}}>{(item.type===3 || item.type===2) ? subStrContent(item.content) : item.content}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -105,20 +105,27 @@ class MergeItem extends Component {
|
|||
? "合并于"
|
||||
: "更新于"}
|
||||
</span>
|
||||
<span className="color-grey-8">{item.pr_time}</span>
|
||||
<Tooltip placement="bottom" title={moment(item.pr_full_time).format("YYYY-MM-DD HH:mm")}><span className="color-grey-8">{item.pr_time}</span></Tooltip>
|
||||
<span className="ml15">
|
||||
{
|
||||
item.pull_request_head &&
|
||||
<Tag className="pr-branch-tag">
|
||||
<Link
|
||||
to={`/${item.is_original ? item.fork_project_user : owner}/${ item.is_original ? item.fork_project_identifier : projectsId }/tree/${turnbar(item.pull_request_head)}`}
|
||||
className="maxW200px task-hide ver-middle" style={{maxWidth:"300px"}}
|
||||
>
|
||||
{item.is_original
|
||||
? item.fork_project_user_name
|
||||
: item.author_name}
|
||||
: {item.pull_request_head}
|
||||
</Link>
|
||||
{
|
||||
item.is_original ?
|
||||
(
|
||||
(item.fork_project_user && item.fork_project_identifier) ?
|
||||
<Link
|
||||
to={`/${ item.fork_project_user }/${ item.fork_project_identifier }/tree/${turnbar(item.pull_request_head)}`}
|
||||
className="maxW200px task-hide ver-middle" style={{maxWidth:"300px"}}
|
||||
>
|
||||
{item.fork_project_user_name || "仓库已删除"} : {item.pull_request_head || "分支已删除"}
|
||||
</Link>
|
||||
:
|
||||
<span>{item.fork_project_user_name || "仓库已删除"} : {item.pull_request_head || "分支已删除"}</span>
|
||||
)
|
||||
:
|
||||
<Link to={`/${ owner }/${ projectsId }/tree/${turnbar(item.pull_request_head)}`} style={{maxWidth:"300px"}}>{item.author_name} :{item.pull_request_head || "分支已删除"}</Link>
|
||||
}
|
||||
</Tag>
|
||||
}
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
Menu,
|
||||
Tag,
|
||||
Button,
|
||||
Alert,
|
||||
Alert,Tooltip
|
||||
} from "antd";
|
||||
import "./merge.css";
|
||||
import RenderHtml from "../../components/render-html";
|
||||
|
|
@ -447,7 +447,7 @@ class MessageCount extends Component {
|
|||
? "合并于"
|
||||
: "更新于"}
|
||||
</span>
|
||||
<span className="color-grey-8 ml5">{data.pr_time}</span>
|
||||
<Tooltip placement="bottom" title={data.issue && data.issue.created_at}><span className="color-grey-8 ml5">{data.pr_time}</span></Tooltip>
|
||||
{
|
||||
open_blockchain && data.attached_issues && data.attached_issues.length>0 ?
|
||||
<span className="color-grey-8 ml25">关联issue:
|
||||
|
|
|
|||
|
|
@ -1,14 +1,22 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Input , Form , Select , Checkbox , Button , Spin , AutoComplete, Modal } from 'antd';
|
||||
import { Input , Form , Select , Checkbox , Button , Spin , AutoComplete, Modal , Radio, Tooltip } from 'antd';
|
||||
import { Base64 } from 'js-base64';
|
||||
import { AlignCenter } from '../Component/layout';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
|
||||
import '../css/index.scss';
|
||||
import './new.scss'
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
const addr={
|
||||
"gitea": "https://docs.gitea.com/development/api-usage",
|
||||
"gitee": "https://forum.gitlink.org.cn/forums/10603/detail",
|
||||
"github": "https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token",
|
||||
"gitlab": "https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html",
|
||||
"gitcode": "https://docs.gitcode.com/docs/users/pat/"
|
||||
}
|
||||
|
||||
const plat=["gitea","gitee","github","gitlab","gitcode"];
|
||||
const Option = Select.Option;
|
||||
class Index extends Component {
|
||||
constructor(props) {
|
||||
|
|
@ -19,7 +27,6 @@ class Index extends Component {
|
|||
gitignoreType: "0",
|
||||
LicensesType: "0",
|
||||
|
||||
mirrorCheck:false,
|
||||
|
||||
CategoryList: undefined,
|
||||
LanguageList: undefined,
|
||||
|
|
@ -57,7 +64,10 @@ class Index extends Component {
|
|||
tokenConTri: false,
|
||||
|
||||
gitHubUrl:false,
|
||||
checkToken:undefined
|
||||
checkToken:"",
|
||||
isToken:true,
|
||||
isPrivate:false,
|
||||
platName:undefined
|
||||
}
|
||||
}
|
||||
componentDidMount = () => {
|
||||
|
|
@ -207,32 +217,35 @@ class Index extends Component {
|
|||
isSpin: true
|
||||
})
|
||||
const { projectsType } = this.props.match.params;
|
||||
const { project_language_id, project_category_id, license_id
|
||||
, ignore_id, owners_id, ignoreFlag, licenseFlag,
|
||||
categoreFlag, languageFlag, tokenConTri,gitHubUrl} = this.state;
|
||||
const { project_language_id, project_category_id, license_id, ignore_id, ignoreFlag,
|
||||
licenseFlag , categoreFlag, languageFlag, tokenConTri, isPrivate,isToken} = this.state;
|
||||
const decoderPass = Base64.encode(values.password);
|
||||
const url = (projectsType && projectsType === "mirror") ? "/projects/migrate.json" : "/projects.json";
|
||||
// 新建项目的时候,暂存数据,如果失败,返回的时候可以重新赋值
|
||||
sessionStorage.newProjectValue=JSON.stringify({...values,project_language_id,project_category_id,license_id,ignore_id});
|
||||
// 贡献值激励确权机制
|
||||
const {blockchain_init} = values;
|
||||
const { clone_addr } = values;
|
||||
axios.post(url, {
|
||||
...values,
|
||||
clone_addr:(projectsType && projectsType === "mirror") ? values.clone_addr.trim() :undefined,
|
||||
clone_addr:(projectsType && projectsType === "mirror") ? clone_addr.trim() :undefined,
|
||||
auth_password:decoderPass,
|
||||
project_language_id:languageFlag ? project_language_id : undefined,
|
||||
project_category_id:categoreFlag ? project_category_id : undefined,
|
||||
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:tokenConTri ? 10000 : undefined,
|
||||
blockchain_init_token: tokenConTri ? parseInt(blockchain_init):undefined,
|
||||
auth_token: isPrivate && isToken ? values.auth_token : undefined,
|
||||
importType:undefined
|
||||
}).then((result) => {
|
||||
if (result && result.data.id) {
|
||||
projectsType && projectsType !== "mirror" && this.props.showNotification(`项目创建成功!`);
|
||||
this.props.history.push({pathname: `/${result.data.login}/${result.data.identifier}`, query:{showNps: true}});
|
||||
setTimeout(() => {
|
||||
this.props.history.push({pathname: `/${result.data.login}/${result.data.identifier}`, query:{showNps: true}});
|
||||
}, 500);
|
||||
}
|
||||
this.setState({
|
||||
isSpin: false
|
||||
|
|
@ -286,16 +299,10 @@ class Index extends Component {
|
|||
callback();
|
||||
}
|
||||
|
||||
changeMirrorCheck=()=>{
|
||||
const { mirrorCheck } = this.state;
|
||||
this.setState({
|
||||
mirrorCheck:!mirrorCheck
|
||||
})
|
||||
}
|
||||
|
||||
ChangeAddr=(e)=>{
|
||||
let value = e.target.value;
|
||||
if(value.indexOf("/") > -1){
|
||||
ChangeAddr=(value,unUpdateName)=>{
|
||||
// 将路径最后一个/后的字符作为项目标识
|
||||
if(value.indexOf("/") > -1 && !unUpdateName){
|
||||
let arr = value.split("/");
|
||||
let first = arr[arr.length-1];
|
||||
if(first.indexOf(".") > -1){
|
||||
|
|
@ -310,9 +317,13 @@ class Index extends Component {
|
|||
repository_name:first
|
||||
})
|
||||
}
|
||||
this.setState({gitHubUrl:value.indexOf("https://github.com")>-1 ? true : false})
|
||||
}else{
|
||||
this.setState({gitHubUrl:false,checkToken:undefined})
|
||||
}
|
||||
// 根据htts://gitlab.com等判断是哪个平台
|
||||
if(value){
|
||||
let name = "";
|
||||
plat.map(i=>{return value.indexOf(`://${i}`)>0 ? name = i :""});
|
||||
name && this.props.form.setFieldsValue({service:name})
|
||||
name && this.setState({platName:name})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -357,8 +368,7 @@ class Index extends Component {
|
|||
}
|
||||
|
||||
|
||||
blurFunc=(e)=>{
|
||||
let value = e.target.value;
|
||||
blurFunc=(rule, value, callback)=>{
|
||||
if(value){
|
||||
const { clone_addr } = this.props.form.getFieldsValue();
|
||||
if(clone_addr){
|
||||
|
|
@ -367,22 +377,23 @@ class Index extends Component {
|
|||
auth_token:value,
|
||||
clone_addr
|
||||
}).then(response=>{
|
||||
if(response && response.data){
|
||||
this.setState({
|
||||
checkToken:response.data.data
|
||||
})
|
||||
let res = response.data;
|
||||
if(res && res.data === false){
|
||||
callback("请输入正确的令牌");
|
||||
}else{
|
||||
callback();
|
||||
}
|
||||
callback();
|
||||
}).catch(error=>{})
|
||||
}
|
||||
}else{
|
||||
this.setState({checkToken:undefined})
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
changeName=(e)=>{
|
||||
let value = e.target.value;
|
||||
const { t } = this.props;
|
||||
console.log(this.props,t(value,'en'));
|
||||
if(value){
|
||||
let reg = /[a-zA-Z0-9]/g;
|
||||
let strArr = value.match(reg);
|
||||
|
|
@ -396,6 +407,29 @@ class Index extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
changeVisibility=(e)=>{
|
||||
let value = e.target.value;
|
||||
let flag = value === "token";
|
||||
this.setState({isToken:flag})
|
||||
let { clone_addr } = this.props.form.getFieldsValue();
|
||||
if(!flag && clone_addr){
|
||||
setTimeout(() => {
|
||||
this.ChangeAddr(clone_addr,true);
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
changeIsPrivate=(e)=>{
|
||||
this.setState({
|
||||
isPrivate:e.target.checked
|
||||
})
|
||||
if(e.target.checked){
|
||||
this.props.form.setFieldsValue({
|
||||
importType:"token"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
// 项目类型:deposit-托管项目,mirror-镜像项目
|
||||
|
|
@ -416,7 +450,6 @@ class Index extends Component {
|
|||
license_list,
|
||||
ignore_list,
|
||||
|
||||
mirrorCheck,
|
||||
|
||||
descNum,
|
||||
|
||||
|
|
@ -425,8 +458,10 @@ class Index extends Component {
|
|||
languageFlag,
|
||||
categoreFlag,
|
||||
tokenConTri,
|
||||
gitHubUrl,
|
||||
checkToken
|
||||
checkToken,
|
||||
isToken,
|
||||
platName,
|
||||
isPrivate
|
||||
} = this.state;
|
||||
return (
|
||||
<div className="main back-white" style={{padding:"0px",border:"none"}}>
|
||||
|
|
@ -448,7 +483,7 @@ class Index extends Component {
|
|||
required: true, message: '请填写镜像版本库地址'
|
||||
}],
|
||||
})(
|
||||
<Input placeholder="请输入需要导入到本项目的仓库地址" onBlur={this.ChangeAddr} />
|
||||
<Input placeholder="请输入需要导入到本项目的仓库地址" onBlur={(e)=>this.ChangeAddr(e.target.value)} />
|
||||
)}
|
||||
</Form.Item>
|
||||
<p className="formTip" style={{color:"#D1d1c9"}}>示例:https://github.com/Stability-AI/StableStudio.git</p>
|
||||
|
|
@ -456,40 +491,55 @@ class Index extends Component {
|
|||
}
|
||||
{
|
||||
projectsType && projectsType === "mirror" &&
|
||||
<div className="pb10">
|
||||
<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 && <a href="https://forum.gitlink.org.cn/forums/8516/detail" className="color-blue" target="_blank">如何获取token?</a>}
|
||||
</span>
|
||||
</p>
|
||||
<div className="mb10">
|
||||
<Form.Item
|
||||
label=""
|
||||
style={{marginBottom:"0px"}}
|
||||
>
|
||||
{getFieldDecorator('isPrivate', {
|
||||
rules: [],
|
||||
})(
|
||||
<Checkbox value="importPrivate" onChange={this.changeIsPrivate}>导入私有项目</Checkbox>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label=""
|
||||
style={{marginBottom:"10px",display:isPrivate?"block":"none"}}
|
||||
>
|
||||
{getFieldDecorator('importType', {
|
||||
rules: [],
|
||||
})(
|
||||
<Radio.Group onChange={this.changeVisibility}>
|
||||
<Radio value="token">访问令牌方式导入</Radio>
|
||||
<Radio value="pwd">用户名+密码方式导入</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
</Form.Item>
|
||||
{/* token导入 */}
|
||||
{
|
||||
mirrorCheck && gitHubUrl &&
|
||||
<div className="df mb10 token_box">
|
||||
<span className="mr10">Token</span>
|
||||
<input type="password" style={{display:"none"}} />
|
||||
<Form.Item
|
||||
style={{ marginBottom: "0px" }}
|
||||
label=""
|
||||
>
|
||||
{getFieldDecorator('auth_token')(
|
||||
<Input placeholder="请输入对应平台的有效token" style={{width:"240px"}} onBlur={this.blurFunc} />
|
||||
)}
|
||||
</Form.Item>
|
||||
<span style={{marginLeft:"-20px"}}>
|
||||
{ checkToken === false && <i className="iconfont icon-cuo color-red"></i>}
|
||||
{ checkToken === true && <i className="iconfont icon-dui color-green"></i>}
|
||||
</span>
|
||||
</div>
|
||||
isToken && isPrivate &&
|
||||
<Form.Item
|
||||
label={<span>访问令牌(Access Token){addr[`${platName && platName.toLowerCase()}`] && <a className='color-blue' href={addr[`${platName.toLowerCase()}`]} target='_blank'>如何配置?</a>}</span>}
|
||||
>
|
||||
{getFieldDecorator('auth_token',{
|
||||
rules: [
|
||||
{required: true, message: '请输入需要导入仓库的访问令牌'},
|
||||
{validator:(rule, value, callback)=>this.blurFunc(rule, value, callback)}
|
||||
],
|
||||
validateTrigger:"onBlur",
|
||||
})(
|
||||
<Input placeholder="请输入需要导入仓库的访问令牌"/>
|
||||
)}
|
||||
</Form.Item>
|
||||
}
|
||||
{
|
||||
mirrorCheck && !gitHubUrl &&
|
||||
<div className="df mb10" style={{alignItems:'center'}}>
|
||||
isPrivate && !isToken &&
|
||||
<div className="df mb20" style={{alignItems:'center'}}>
|
||||
{/* 用户名密码导入 */}
|
||||
<span className="mr10">用户名</span>
|
||||
<input type="password" style={{display:"none"}} />
|
||||
<Form.Item
|
||||
style={{ marginBottom: "0px" }}
|
||||
style={{ marginBottom: "0px"}}
|
||||
label=""
|
||||
>
|
||||
{getFieldDecorator('auth_username', {
|
||||
|
|
|
|||