测试 测试 #4

Closed
Eeeros wants to merge 296 commits from gitlink_ssr_head into pre_gitlink_ssr
222 changed files with 5838 additions and 27890 deletions

View File

@ -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"]

View File

@ -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: {

23452
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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"
},

View File

@ -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
public/css/detail.css Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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";
}

File diff suppressed because one or more lines are too long

View File

@ -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",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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 || [];

View File

@ -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();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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) {

View File

@ -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
}

View File

@ -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
}

View File

@ -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);
// });

View File

@ -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));

View File

@ -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');
}
}
}

View File

@ -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.$;

View File

@ -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>

View File

@ -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'

View File

@ -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

View File

@ -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'

View File

@ -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];

View File

@ -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]);

View File

@ -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 ;
}
}
}
}

View File

@ -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 ;
}

View File

@ -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;

View File

@ -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">

View File

@ -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>
}

View File

@ -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>
)

View File

@ -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>

View File

@ -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>
)
}

View File

@ -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;

View File

@ -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>
)
}

View File

@ -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>
}

View File

@ -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) {
}

View File

@ -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

View File

@ -14,7 +14,7 @@
cursor: pointer;
transition: 1s;
.grow_path_type {
width: 82px;
// width: 82px;
height: 58px;
// color: black;
font-size: 15px;

View File

@ -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>

View File

@ -162,7 +162,7 @@
flex-direction: column;
justify-content: space-between;
}
.title{
.title_JCC{
font-size: 20px;
margin: 10px 0;
}

View File

@ -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>

View File

@ -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}}>常开域LCLKGENWatchDogPMURTC</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'>存储ROMSRAMDRAMNAND/NOR FlashDDR</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>
)
}

View File

@ -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);
// sidebarlist
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>

View File

@ -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>
)
}
})

View File

@ -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:"请输入内容!"}],

View File

@ -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>
}

View File

@ -25,7 +25,6 @@ function NewsList(props){
const [ menuSpin , setMenuSpin ] = useState(true);
const { id, temp } = props;
useEffect(()=>{
if(id && cateId ){
setMenuSpin(true);

View File

@ -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(()=>{

View File

@ -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',
})
}

View File

@ -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;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -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();
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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}&nbsp;</Link>

View File

@ -25,6 +25,7 @@ function NewPanel(props,ref){
},[title , desc , files])
function onContentChange(value){
console.log("-----------------",value);
setDescription(value);
}
function UploadFunc(f){

View File

@ -185,6 +185,7 @@ function Sign(props){
}
function createSign(){
setEditId(undefined);
const c = Math.random().toString(16).substr(-6);
c && setDefaultColor(`#${c}`);
setEdit(true);

View File

@ -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>
)
}

View File

@ -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>
)
}

View File

@ -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)}>

View File

@ -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) {

View File

@ -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'),

View File

@ -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));

View File

@ -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;
}
}

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -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;

View File

@ -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>

View File

@ -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(()=>{

View File

@ -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>
)

View File

@ -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>
)
}

View File

@ -275,8 +275,8 @@ class CreateMerge extends Component {
let _url = `/${mergeOwner}/${projectId}/compare/`;
// type为pull时pullBranch取value否则取原有值
// type为pull时mergeBranch取原有值否则取value
let _pullBranch = type === 'pull' ? value : pullBranch;
let _mergeBranch = type === 'pull' ? mergeBranch : value;
let _pullBranch = type === 'pull' ? value : returnbar(pullBranch);
let _mergeBranch = type === 'pull' ? returnbar(mergeBranch) : value;
if (pullOwner === mergeOwner) {
// 如果仓库相同, compare/目标分支...源分支
_url += `${turnbar(_mergeBranch)}...${turnbar(_pullBranch)}`;

View File

@ -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>
)

View File

@ -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>
}
{

View File

@ -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:

View File

@ -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', {

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