This commit is contained in:
parent
cb21d82b75
commit
96475ab739
18
Routes.js
18
Routes.js
|
|
@ -1,11 +1,19 @@
|
|||
import Detail from "./src/forge/Main/DetailAdaptor";
|
||||
|
||||
import app from './src/App'
|
||||
import users from './src/forge/users/Index';
|
||||
import Detail from "./src/forge/Main/Detail";
|
||||
|
||||
export default [
|
||||
{
|
||||
key:"detail",
|
||||
path: "/:owner/:projectsId",
|
||||
exact: true,
|
||||
component: app,
|
||||
}
|
||||
];
|
||||
|
||||
export const deepRoutes = [
|
||||
{
|
||||
key:"detail",
|
||||
path: "/:owner/:projectsId",
|
||||
component: Detail,
|
||||
},
|
||||
];
|
||||
}
|
||||
]
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
"use strict";
|
||||
const autoprefixer = require("autoprefixer");
|
||||
const path = require("path");
|
||||
import { ReactLoadablePlugin } from 'react-loadable/webpack';
|
||||
const webpack = require("webpack");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
|
|
@ -29,9 +30,9 @@ const terserPlugin = new TerserWebpackPlugin({
|
|||
terserOptions: {
|
||||
compress: {
|
||||
warnings: false,
|
||||
drop_console: true,
|
||||
drop_console: false,
|
||||
drop_debugger: true,
|
||||
pure_funcs: ['console.log'] //移除console
|
||||
// pure_funcs: ['console.log'] //移除console
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -117,6 +118,9 @@ module.exports = {
|
|||
// please link the files into your node_modules/ and let module-resolution kick in.
|
||||
// Make sure your source files are compiled, as they will not be processed in any way.
|
||||
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
|
||||
new ReactLoadablePlugin({
|
||||
filename: './react-loadable.json',
|
||||
}),
|
||||
// ["transform-remove-console"]
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ const serverConfig = {
|
|||
externals: [
|
||||
nodeExternals(), // 忽略 Node.js 核心模块
|
||||
// 自定义的外部模块
|
||||
{ 'alex': 'Alex', "react": "React", "react-dom": "ReactDOM" }
|
||||
{ "react": "React", "react-dom": "ReactDOM" }
|
||||
],
|
||||
resolve: {
|
||||
// This allows you to set a fallback for where Webpack should look for modules.
|
||||
|
|
@ -101,7 +101,7 @@ const serverConfig = {
|
|||
{
|
||||
test: /\.(js|jsx|mjs)$/,
|
||||
include: [paths.appSrc, paths.serverSrc],
|
||||
exclude: /node_modules/,
|
||||
// exclude: /node_modules/,
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
cacheDirectory: true,
|
||||
|
|
|
|||
|
|
@ -7369,6 +7369,58 @@
|
|||
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
|
||||
"dev": true
|
||||
},
|
||||
"connect-timeout": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmmirror.com/connect-timeout/-/connect-timeout-1.9.0.tgz",
|
||||
"integrity": "sha512-q4bsBIPd+eSGtnh/u6EBOKfuG+4YvwsN0idlOsg6KAw71Qpi0DCf2eCc/Va63QU9qdOeYC8katxoC+rHMNygZg==",
|
||||
"requires": {
|
||||
"http-errors": "~1.6.1",
|
||||
"ms": "2.0.0",
|
||||
"on-finished": "~2.3.0",
|
||||
"on-headers": "~1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="
|
||||
},
|
||||
"http-errors": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-1.6.3.tgz",
|
||||
"integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==",
|
||||
"requires": {
|
||||
"depd": "~1.1.2",
|
||||
"inherits": "2.0.3",
|
||||
"setprototypeof": "1.1.0",
|
||||
"statuses": ">= 1.4.0 < 2"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="
|
||||
},
|
||||
"on-finished": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.3.0.tgz",
|
||||
"integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
|
||||
"requires": {
|
||||
"ee-first": "1.1.1"
|
||||
}
|
||||
},
|
||||
"setprototypeof": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
||||
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
|
||||
},
|
||||
"statuses": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz",
|
||||
"integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"connected-react-router": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/connected-react-router/-/connected-react-router-4.4.1.tgz",
|
||||
|
|
@ -12148,7 +12200,7 @@
|
|||
},
|
||||
"http-proxy": {
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmmirror.com/http-proxy/-/http-proxy-1.18.1.tgz",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/http-proxy/-/http-proxy-1.18.1.tgz",
|
||||
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
|
||||
"requires": {
|
||||
"eventemitter3": "^4.0.0",
|
||||
|
|
@ -12158,7 +12210,7 @@
|
|||
"dependencies": {
|
||||
"eventemitter3": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
||||
}
|
||||
}
|
||||
|
|
@ -12218,12 +12270,12 @@
|
|||
},
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
|
|
@ -13778,6 +13830,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmmirror.com/jquery/-/jquery-3.7.1.tgz",
|
||||
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
|
||||
},
|
||||
"js-base64": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "http://173.15.15.82:8081/repository/npm-all/js-base64/-/js-base64-2.6.4.tgz",
|
||||
|
|
@ -15635,8 +15692,7 @@
|
|||
"on-headers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
|
||||
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
"clipboard": "^2.0.8",
|
||||
"code-prettify": "^0.1.0",
|
||||
"codemirror": "^5.64.0",
|
||||
"connect-timeout": "^1.9.0",
|
||||
"connected-react-router": "4.4.1",
|
||||
"core-js": "^3.34.0",
|
||||
"dompurify": "^2.3.3",
|
||||
|
|
@ -60,6 +61,7 @@
|
|||
"intersection-observer": "^0.12.2",
|
||||
"isomorphic-style-loader": "^5.3.2",
|
||||
"jest": "20.0.4",
|
||||
"jquery": "^3.7.1",
|
||||
"js-base64": "^2.5.2",
|
||||
"js2wordcloud": "^1.1.12",
|
||||
"jsdom": "^15.2.1",
|
||||
|
|
@ -141,7 +143,7 @@
|
|||
"xterm-addon-fit": "0.4.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node --max_old_space_size=15360 scripts/start.js",
|
||||
"start": "node scripts/start.js",
|
||||
"build": "cross-env NODE_ENV=production babel-node --max_old_space_size=15360 scripts/build.js",
|
||||
"build:dll": "webpack --config=./config/webpack.dll.config.js",
|
||||
"test-build": "cross-env NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js",
|
||||
|
|
@ -152,7 +154,7 @@
|
|||
"analyz": "NODE_ENV=production npm_config_report=true npm run build",
|
||||
"dev": "npm-run-all --parallel dev:**",
|
||||
"dev:server": "cross-env NODE_ENV=production nodemon --exec babel-node \"./buildserver/bundle.js\" --watch config --watch server",
|
||||
"dev:build:server": "cross-env NODE_ENV=production webpack --config config/webpack.server.js --watch"
|
||||
"dev:build:server": "cross-env NODE_ENV=production webpack --config config/webpack.server.js"
|
||||
},
|
||||
"jest": {
|
||||
"collectCoverageFrom": [
|
||||
|
|
|
|||
|
|
@ -11,15 +11,31 @@ const targetServer = 'https://www.gitlink.org.cn'; // Java 服务器的地址
|
|||
const options = {
|
||||
target: targetServer,
|
||||
changeOrigin: true, // 允许在请求头中更改主机
|
||||
timeout: 30000
|
||||
};
|
||||
|
||||
// 设置代理
|
||||
app.use('/api', (req, res) => {
|
||||
app.use(['/api', '/images', '/system', '/favicon'], (req, res) => {
|
||||
const proxy = createProxyMiddleware(options);
|
||||
proxy(req, res);
|
||||
});
|
||||
|
||||
// 中间件,用于排除特定的路径
|
||||
function excludePath(req, res, next) {
|
||||
// 检查请求的路径是否需要被排除
|
||||
if (req.path.includes('/build/')) {
|
||||
// 如果是,直接结束请求,不调用下一个中间件或路由处理器
|
||||
res.status(404).send('This path is excluded.');
|
||||
} else {
|
||||
// 如果不是,继续执行下一个中间件或路由处理器
|
||||
next();
|
||||
}
|
||||
}
|
||||
// 应用中间件到所有路由
|
||||
app.use(excludePath);
|
||||
|
||||
app.get('*',function (req,res) {
|
||||
console.log('render', req.url)
|
||||
render(req,res);
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,85 @@
|
|||
import React from "react";
|
||||
import {renderToString} from "react-dom/server";
|
||||
import {StaticRouter} from "react-router-dom";
|
||||
import {renderRoutes} from "react-router-config";
|
||||
import Routes from "../Routes";
|
||||
import { Provider } from "react-redux";
|
||||
import fs from 'fs'
|
||||
import path from 'path';
|
||||
import {StaticRouter, matchPath} from "react-router-dom";
|
||||
|
||||
export const render = (req,res)=>{
|
||||
const context = {
|
||||
css: []
|
||||
import {renderRoutes} from "react-router-config";
|
||||
import Routes, { deepRoutes } from "../Routes";
|
||||
import { Provider } from "react-redux";
|
||||
import { getPathType } from './service'
|
||||
import { serverStore } from "../src/redux/stores/configureStore";
|
||||
import App from "../src/App";
|
||||
import { Route } from 'react-router-dom';
|
||||
|
||||
export const render = async (req,res)=>{
|
||||
let _route = null,
|
||||
_match = null;
|
||||
|
||||
const pathData = await getPathType('Eeeros')
|
||||
const store = serverStore();
|
||||
|
||||
|
||||
function matchSubRoutes(routes, url) {
|
||||
for (const route of routes) {
|
||||
// 检查当前路由是否匹配
|
||||
let match = matchPath(url, route.path);
|
||||
if (match) {
|
||||
// 如果当前路由匹配,并且它有子路由,递归检查子路由
|
||||
if (route.routes) {
|
||||
// 递归调用匹配子路由
|
||||
const subMatch = matchSubRoutes(route.routes, url);
|
||||
if (subMatch) {
|
||||
_route = route;
|
||||
_match = subMatch;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 如果没有子路由,或者子路由不匹配,但当前路由匹配,返回当前路由
|
||||
_route = route;
|
||||
_match = match;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 如果没有找到匹配的路由,返回false
|
||||
return false;
|
||||
}
|
||||
|
||||
matchSubRoutes(deepRoutes, req.url.split("?")[0])
|
||||
|
||||
let context = {
|
||||
code: 200,
|
||||
};
|
||||
|
||||
|
||||
if (_route && _route.component && _route.component.preFetch) {
|
||||
context = await _route.component.preFetch({
|
||||
store,
|
||||
match: _match,
|
||||
query: req.path,
|
||||
});
|
||||
}
|
||||
|
||||
const content = renderToString((
|
||||
<Provider>
|
||||
<StaticRouter location={req.path} context={context}>{renderRoutes(Routes)}</StaticRouter>
|
||||
<Provider store={store}>
|
||||
<StaticRouter location={req.path} context={context}>
|
||||
<Route path='/:owner/:projectsId' exact component={App}></Route>
|
||||
</StaticRouter>
|
||||
</Provider>
|
||||
))
|
||||
|
||||
let html=fs.readFileSync(path.join(path.resolve('./build'),'index.html'),'utf-8');
|
||||
|
||||
// 注入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)=>{
|
||||
data=data.replace('<div id="root" class="page -layout-v -fit widthunit"></div>',`<div id="root" class="page -layout-v -fit widthunit">${rootString}</div>`);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import axios from "axios";
|
||||
|
||||
const instance = axios.create({
|
||||
baseURL: 'https://www.gitlink.org.cn', // 你的API基础URL
|
||||
timeout: 20000, // 请求超时时间
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// 封装GET请求
|
||||
function get(url, params) {
|
||||
return instance.get(url, { params }).then(response => response.data);
|
||||
}
|
||||
|
||||
// 封装POST请求
|
||||
function post(url, data) {
|
||||
return instance.post(url, data).then(response => response.data);
|
||||
}
|
||||
|
||||
// 封装PUT请求
|
||||
function put(url, data) {
|
||||
return instance.put(url, data).then(response => response.data);
|
||||
}
|
||||
|
||||
// 封装DELETE请求
|
||||
function deleteRequest(url) {
|
||||
return instance.delete(url).then(response => response.data);
|
||||
}
|
||||
|
||||
export const getPathType = (pathname) => {
|
||||
return get(`/api/owners/${pathname}.json`)
|
||||
}
|
||||
|
|
@ -1,14 +1,30 @@
|
|||
const jsdom = require("jsdom");
|
||||
import fs from 'fs'
|
||||
import path from 'path';
|
||||
import axios from "axios";
|
||||
|
||||
const { JSDOM } = jsdom;
|
||||
|
||||
const html=fs.readFileSync(path.join(path.resolve('./build'),'index.html'),'utf-8');
|
||||
|
||||
const html = fs.readFileSync(path.join(path.resolve('./build'),'index.html'),'utf-8');
|
||||
const dom = new JSDOM(html);
|
||||
const { window } = dom;
|
||||
|
||||
const $ = require( "jquery" )( window )
|
||||
|
||||
global.window = window;
|
||||
global.domObj = dom;
|
||||
global.document = window.document;
|
||||
global.navigator = window.navigator;
|
||||
global.localStorage = {}
|
||||
|
||||
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);
|
||||
});
|
||||
|
|
|
|||
14
src/App.js
14
src/App.js
|
|
@ -22,11 +22,9 @@ import SiderBarHelp from './glcc/siderBarHelp';
|
|||
|
||||
import { SnackbarHOC } from 'educoder';
|
||||
import { initAxiosInterceptors } from './AppConfig'
|
||||
import { Provider } from 'react-redux';
|
||||
import configureStore from './redux/stores/configureStore';
|
||||
import cookie from 'react-cookies';
|
||||
import InfosIndex from './forge/users/Index'
|
||||
|
||||
const store = configureStore();
|
||||
window.marked = marked;
|
||||
const theme = createMuiTheme({
|
||||
palette: {
|
||||
|
|
@ -77,10 +75,10 @@ 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'),
|
||||
|
|
@ -328,7 +326,6 @@ class App extends Component {
|
|||
render() {
|
||||
const { pathType, pathName, mygetHelmetapi } = this.state;
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<ConfigProvider locale={zhCN}>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
|
||||
|
|
@ -536,7 +533,6 @@ class App extends Component {
|
|||
</Switch>
|
||||
</MuiThemeProvider>
|
||||
</ConfigProvider>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ function locationurl(list) {
|
|||
// TODO 开发期多个身份切换
|
||||
let debugType = ""
|
||||
if (isDev) {
|
||||
const _search = window.location.search;
|
||||
let parsed = {};
|
||||
if (_search) {
|
||||
parsed = queryString.parse(_search);
|
||||
}
|
||||
debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' :
|
||||
window.location.search.indexOf('debug=s') !== -1 ? 'student' :
|
||||
window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
|
||||
// const _search = window.location.search;
|
||||
// let parsed = {};
|
||||
// if (_search) {
|
||||
// parsed = queryString.parse(_search);
|
||||
// }
|
||||
// debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' :
|
||||
// window.location.search.indexOf('debug=s') !== -1 ? 'student' :
|
||||
// window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
|
||||
}
|
||||
window._debugType = debugType;
|
||||
export function initAxiosInterceptors(props) {
|
||||
|
|
@ -56,6 +56,7 @@ export function initAxiosInterceptors(props) {
|
|||
// }
|
||||
// }
|
||||
config.url = url;
|
||||
console.log(config.url)
|
||||
config.withCredentials = false;
|
||||
return config;
|
||||
},
|
||||
|
|
@ -95,13 +96,14 @@ export function initAxiosInterceptors(props) {
|
|||
}
|
||||
|
||||
if (response.data.status === 404) {
|
||||
let responseURL = response.request ? response.request.responseURL:'';
|
||||
let responseURL = (response && response.request) ? response.request.responseURL:'';
|
||||
// 组织和个人的拥有情况,404不跳转
|
||||
console.log(responseURL)
|
||||
if (responseURL.indexOf('/api/users/') === -1 && responseURL.indexOf('/api/organizations/') === -1 ) {
|
||||
// 邀请页面不进行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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -348,7 +348,13 @@ export function setSeoMeta(keyWords, title, description, url, owner, projectId)
|
|||
if(owner)keyStatement += owner;
|
||||
if(projectId)keyStatement += `/${projectId}`;
|
||||
|
||||
if (domObj) {
|
||||
console.log('==================domObj===================')
|
||||
document = domObj.window.document
|
||||
console.log('==================document===================', document.querySelector(`meta[property='og:title']`).content)
|
||||
}
|
||||
document.querySelector(`meta[property='og:title']`).content = title + keyStatement + ' for gitlink' + keyStatement + ' for git';
|
||||
console.log('==================document===================', document.querySelector(`meta[property='og:title']`).content)
|
||||
document.querySelector(`meta[property='og:url']`).content = window.location.origin + url;
|
||||
document.querySelector(`meta[property='og:description']`).content = description + ' - ' + title + ' for gitlink' + keyStatement + ' for git';
|
||||
document.querySelector(`meta[property='og:image:alt']`).content = description + ' - ' + title + ' for gitlink' + keyStatement + ' for git';
|
||||
|
|
@ -364,5 +370,7 @@ export function setSeoMeta(keyWords, title, description, url, owner, projectId)
|
|||
document.querySelector(`meta[name='twitter:description']`).content = description + ' - ' + title + keyStatement + ' for gitlink' + keyStatement + ' for git';
|
||||
|
||||
document.querySelector(`link[rel='canonical']`).href = window.location.origin + url;
|
||||
|
||||
if (domObj) {
|
||||
domObj.window.document.querySelector('meta[name="Keywords"]')
|
||||
}
|
||||
}
|
||||
|
|
@ -56,6 +56,7 @@ export default ({
|
|||
}
|
||||
|
||||
let str = String(value);
|
||||
console.log(str)
|
||||
const html = useMemo(() => {
|
||||
let rs = marked(str);
|
||||
const math_expressions = getMathExpressions();
|
||||
|
|
@ -104,6 +105,7 @@ export default ({
|
|||
rs = dompurify.sanitize(rs.replace(/▁/g, "▁▁▁"))
|
||||
rs = rs.replaceAll('<img ', `<img onerror="javascript:this.src='${ imgError }';"`)
|
||||
resetMathExpressions()
|
||||
console.log('==========================rs=====================', rs)
|
||||
return rs
|
||||
}, [str,issues]);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ
|
|||
import { Dropdown , Menu , Divider , Spin, Button , Typography } from 'antd';
|
||||
import { getImageUrl , turnbar , returnbar } from "educoder";
|
||||
import { Link } from 'react-router-dom';
|
||||
import { connect } from 'react-redux';
|
||||
import { truncateCommitId } from "../common/util";
|
||||
import CloneAddress from '../Branch/CloneAddress';
|
||||
|
||||
|
|
@ -12,7 +13,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';
|
||||
|
|
@ -28,30 +29,35 @@ import RenderHtml from '../../components/render-html';
|
|||
*/
|
||||
function CoderDepot(props){
|
||||
// const [ projectDetail , setProjectDetail ]= useState(undefined);
|
||||
const [ inviteCode , setInviteCode ] = useState(undefined);
|
||||
let { platform , mirror_status , bannerList , projectDetail, projectEntries, projectReadMe } = props ;
|
||||
console.log('==================projectReadMe=========', projectReadMe)
|
||||
|
||||
projectDetail = props.defaultDetail || projectDetail || {}
|
||||
|
||||
const [ inviteCode , setInviteCode ] = useState(projectDetail.invite_code || undefined);
|
||||
const [ treeValue , setTreeValue ] = useState(undefined);
|
||||
const [ treeValuePath , setTreeValuePath ] = useState(undefined);
|
||||
const [ lastCommit,setLastCommit ] = useState(undefined);
|
||||
const [ lastCommitAuthor,setLastCommitAuthor ] = useState(undefined);
|
||||
const [ lastCommit,setLastCommit ] = useState((projectEntries.last_commit && projectEntries.last_commit.commit) || undefined);
|
||||
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 [ commitCount ,setCommitCount ] = useState(0);
|
||||
const [ dirInfo ,setDirInfo ] = useState(undefined);//文件夹目录列表
|
||||
const [ commitCount ,setCommitCount ] = useState(projectEntries.commits_count || 0);
|
||||
const [ dirInfo ,setDirInfo ] = useState(projectEntries.entries || undefined);//文件夹目录列表
|
||||
const [ fileInfo ,setFileInfo ] = useState(undefined);//文件内容信息
|
||||
const [ zip_url , setZip_url ] = useState(undefined);
|
||||
const [ tar_url , setTar_url ] = useState(undefined);
|
||||
const [ zip_url , setZip_url ] = useState(projectEntries.zip_url || undefined);
|
||||
const [ tar_url , setTar_url ] = useState(projectEntries.tar_url || undefined);
|
||||
const [ readOnly , setReadOnly] = useState(undefined);
|
||||
const [ isSpin , setIsSpin] = useState(false);
|
||||
const [ visible ,setVisible ] = useState(false);
|
||||
const [ mainFlag ,setMainFlag ] = useState(false);
|
||||
const [ openModal , setOpenModal ] = useState(false);
|
||||
const [ desc , setDesc ] = useState(undefined);
|
||||
const [ website , setWebsite ] = useState(undefined);
|
||||
const [ lesson_url , setLessonUrl ] = useState(undefined);
|
||||
const [ topics, setTopics] = useState(undefined);
|
||||
const [ readme , setReadme ] = useState(undefined);
|
||||
const [ defaultBranch , setDefaultBranch ] = useState(undefined);
|
||||
const [ desc , setDesc ] = useState(projectDetail.description || undefined);
|
||||
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 [ defaultBranch , setDefaultBranch ] = useState(projectDetail.default_branch || undefined);
|
||||
const [ editReadme , setEditReadme ] = useState(false);
|
||||
const [ pullsFlag , setPullsFlag ] = useState(true);
|
||||
const [ issuesFlag , setIssuesFlag ] = useState(true);
|
||||
|
|
@ -63,7 +69,6 @@ function CoderDepot(props){
|
|||
branchName = returnbar(branchName);
|
||||
let pathname = props.history.location.pathname;
|
||||
let search = props.history.location.search
|
||||
const { platform , mirror_status , bannerList , projectDetail } = props ;
|
||||
//distribution:判断此用户是否可以创建发行版
|
||||
const distribution = projectDetail && projectDetail.type ===0 && ( projectDetail.permission && projectDetail.permission !== "Reporter");
|
||||
|
||||
|
|
@ -109,9 +114,9 @@ function CoderDepot(props){
|
|||
const { author, name, description, default_branch} = projectDetail;
|
||||
if(branchName && branchName !== default_branch){
|
||||
// 处于某分支/标签
|
||||
document.title = `${author.name}/${name}-${branchName}-for gitlink;for git`;
|
||||
document.title = `${author && author.name}/${name}-${branchName}-for gitlink;for git`;
|
||||
}else{
|
||||
document.title = `${author.name}/${name}${description?': '+description:''}-for gitlink;for git` ;
|
||||
document.title = `${author && author.name}/${name}${description?': '+description:''}-for gitlink;for git` ;
|
||||
}
|
||||
}
|
||||
}, [treeValuePath, projectDetail, branchName])
|
||||
|
|
@ -134,7 +139,9 @@ function CoderDepot(props){
|
|||
setType("file");
|
||||
}else{
|
||||
setTreeValue(undefined);
|
||||
getDirInfo(branchName || defaultBranch);
|
||||
if (!projectEntries) {
|
||||
getDirInfo(branchName || defaultBranch);
|
||||
}
|
||||
setType("dir");
|
||||
}
|
||||
}
|
||||
|
|
@ -142,8 +149,8 @@ function CoderDepot(props){
|
|||
|
||||
// 编辑完回来重新获取
|
||||
useEffect(()=>{
|
||||
if (projectsId && owner && defaultBranch && mirror_status===0 && !search){
|
||||
let b = turnbar(branchName) ;
|
||||
let b = turnbar(branchName) ;
|
||||
if (projectsId && owner && defaultBranch && mirror_status===0 && !search && pathname.indexOf(`/tree/${b}/`) > -1){
|
||||
let url = pathname.split(`/tree/${b}/`)[1];
|
||||
getFileInfo(url,branchName);
|
||||
}
|
||||
|
|
@ -565,18 +572,18 @@ function CoderDepot(props){
|
|||
})
|
||||
}
|
||||
{
|
||||
fileInfo &&
|
||||
<CoderRootFileDetail
|
||||
{...props}
|
||||
detail={fileInfo}
|
||||
readOnly={readOnly}
|
||||
md={mdFlag}
|
||||
onEdit={onEdit}
|
||||
currentBranch={branchName || defaultBranch}
|
||||
branch={branchName || defaultBranch}
|
||||
type={projectDetail.type}
|
||||
treeValuePath={treeValuePath}
|
||||
></CoderRootFileDetail>
|
||||
// fileInfo &&
|
||||
// <CoderRootFileDetail
|
||||
// {...props}
|
||||
// detail={fileInfo}
|
||||
// readOnly={readOnly}
|
||||
// md={mdFlag}
|
||||
// onEdit={onEdit}
|
||||
// currentBranch={branchName || defaultBranch}
|
||||
// branch={branchName || defaultBranch}
|
||||
// type={projectDetail.type}
|
||||
// treeValuePath={treeValuePath}
|
||||
// ></CoderRootFileDetail>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -671,4 +678,20 @@ function CoderDepot(props){
|
|||
</WhiteBack>
|
||||
)
|
||||
}
|
||||
export default CoderDepot;
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const {
|
||||
defaultDetail,
|
||||
projectEntries,
|
||||
projectReadMe
|
||||
} = state.projectReducer;
|
||||
return {
|
||||
defaultDetail,
|
||||
projectEntries,
|
||||
projectReadMe
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps
|
||||
)(CoderDepot);
|
||||
|
|
@ -2,11 +2,14 @@ import React, { Component } from 'react';
|
|||
import { Spin, Tooltip } from 'antd';
|
||||
import { Link, Route, Switch } from 'react-router-dom';
|
||||
import { withRouter } from "react-router";
|
||||
import { connect } from 'react-redux';
|
||||
import { Content, AlignTop } from '../Component/layout';
|
||||
import DetailBanner from './sub/DetailBanner';
|
||||
import CoderDepot from './CoderDepot'
|
||||
import cookie from 'react-cookies';
|
||||
import { setSeoMeta } from 'educoder';
|
||||
import { Base64 } from 'js-base64';
|
||||
import { setProject, setProjectDetail, setProjectEntries, setProjectMenuList, setProjectReadMe } from '../../redux/actions/server';
|
||||
import '../css/index.scss'
|
||||
import './list.scss';
|
||||
|
||||
|
|
@ -15,6 +18,7 @@ import Loadable from 'react-loadable';
|
|||
import Loading from '../../Loading';
|
||||
|
||||
import axios from 'axios';
|
||||
import { async } from 'q';
|
||||
|
||||
const Setting = Loadable({
|
||||
loader: () => import('../Settings/Index'),
|
||||
|
|
@ -88,10 +92,10 @@ const CoderRootCommit = Loadable({
|
|||
loader: () => import('./CoderRootCommit'),
|
||||
loading: Loading,
|
||||
})
|
||||
const CoderDepot = Loadable({
|
||||
loader: () => import('./CoderDepot'),
|
||||
loading: Loading,
|
||||
})
|
||||
// const CoderDepot = Loadable({
|
||||
// loader: () => import('./CoderDepot'),
|
||||
// loading: Loading,
|
||||
// })
|
||||
|
||||
const TrendsIndex = Loadable({
|
||||
loader: () => import('../Activity/Activity'),
|
||||
|
|
@ -163,11 +167,28 @@ function checkPathname(projectsId, owner, pathname) {
|
|||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
const getProjectFunc = (owner, projectsId, isServer = false) => {
|
||||
const url = isServer ? `https://www.gitlink.org.cn/api/${owner}/${projectsId}/simple.json` : `/${owner}/${projectsId}/simple.json`;
|
||||
return axios.get(url)
|
||||
}
|
||||
|
||||
const getDetailFunc = (owner, projectsId, isServer = false) => {
|
||||
const url = isServer ? `https://www.gitlink.org.cn/api/${owner}/${projectsId}/detail.json` : `/${owner}/${projectsId}/detail.json`;
|
||||
return axios.get(url)
|
||||
}
|
||||
|
||||
const getBannerFunc = (owner, projectsId, isServer = false) => {
|
||||
const url = isServer ? `https://www.gitlink.org.cn/api/${owner}/${projectsId}/menu_list.json` : `/${owner}/${projectsId}/menu_list.json`;
|
||||
return axios.get(url)
|
||||
}
|
||||
|
||||
class Detail extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
console.log('=================defaultDetail================', props.defaultDetail)
|
||||
this.state = {
|
||||
projectDetail: undefined,
|
||||
projectDetail: props.defaultDetail || undefined,
|
||||
isManager: false,
|
||||
isReporter: false,
|
||||
isDeveloper: false,
|
||||
|
|
@ -180,7 +201,7 @@ class Detail extends Component {
|
|||
http_url: undefined,
|
||||
branchs: undefined,
|
||||
branchList: undefined,
|
||||
project: null,
|
||||
project: props.projectBase || undefined,
|
||||
firstSync: false,
|
||||
secondSync: false,
|
||||
open_devops: false,
|
||||
|
|
@ -190,22 +211,27 @@ class Detail extends Component {
|
|||
|
||||
// 非本平台项目
|
||||
platform: false,
|
||||
mirror_status:2
|
||||
mirror_status:2,
|
||||
bannerList: props.projectMenu || []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
componentDidMount = () => {
|
||||
this.getProject();
|
||||
// this.getProject();
|
||||
let history = this.props.location;
|
||||
this.clearIssueCookies(history);
|
||||
}
|
||||
|
||||
componentDidUpdate = (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)) {
|
||||
this.getProject();
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
const data = await getProjectFunc(owner, projectsId);
|
||||
if (data.data) {
|
||||
this.getProject(data.data)
|
||||
}
|
||||
}
|
||||
|
||||
this.props.history.listen((history) => {
|
||||
|
|
@ -223,56 +249,77 @@ class Detail extends Component {
|
|||
cookie.save('issuestates', undefined, { expires: 0, path: `/` });
|
||||
}
|
||||
}
|
||||
async componentWillMount() {
|
||||
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
|
||||
if (!this.props.projectBase) {
|
||||
const data = await getProjectFunc(owner, projectsId);
|
||||
console.log('======================getProjectFunc==============')
|
||||
if (data.data) {
|
||||
this.getProject(data.data)
|
||||
}
|
||||
} else {
|
||||
console.log('======================this.props.projectBase==============')
|
||||
this.getProject(this.props.projectBase)
|
||||
}
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.timerChannel && clearTimeout(this.timerChannel);
|
||||
}
|
||||
|
||||
getProject = (num) => {
|
||||
getProject = async (data) => {
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
const url = `/${owner}/${projectsId}/simple.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result && result.data) {
|
||||
this.setState({
|
||||
project: result.data,
|
||||
open_devops: result.data.open_devops,
|
||||
platform: result.data.platform && result.data.platform !== 'educoder'
|
||||
})
|
||||
if (result.data.type !== 0 && result.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({
|
||||
mirror_status:1
|
||||
})
|
||||
} else if (result.data.mirror_status === 2) {
|
||||
this.setState({
|
||||
mirror_status:2,
|
||||
firstSync: false
|
||||
})
|
||||
this.deleteProjectBack();
|
||||
} else {
|
||||
this.setState({
|
||||
firstSync: false,
|
||||
secondSync: false,
|
||||
mirror_status:0
|
||||
})
|
||||
this.getBanner();
|
||||
this.getDetail();
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
project: data,
|
||||
open_devops: data.open_devops,
|
||||
platform: data.platform && data.platform !== 'educoder'
|
||||
})
|
||||
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({
|
||||
mirror_status:1
|
||||
})
|
||||
} else if (data.mirror_status === 2) {
|
||||
this.setState({
|
||||
mirror_status:2,
|
||||
firstSync: false
|
||||
})
|
||||
this.deleteProjectBack();
|
||||
} else {
|
||||
this.setState({
|
||||
firstSync: false,
|
||||
secondSync: false,
|
||||
mirror_status:0
|
||||
})
|
||||
console.log('==================projectMenu=========', this.props.projectMenu)
|
||||
this.getBanner(this.props.projectMenu)
|
||||
let projectdata
|
||||
if (this.props.defaultDetail) {
|
||||
console.log('========================this.props.defaultDetail=================')
|
||||
projectdata = this.props.defaultDetail
|
||||
} else {
|
||||
console.log('========================getDetailFunc=================')
|
||||
projectdata = await getDetailFunc(owner, projectsId, !window.location.host).data;
|
||||
}
|
||||
if (projectdata) {
|
||||
console.log('========================projectdata=================')
|
||||
this.getDetail(projectdata)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 工作流激活后修改状态
|
||||
|
|
@ -356,58 +403,68 @@ class Detail extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
getDetail = () => {
|
||||
getDetail = async (data) => {
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
const url = `/${owner}/${projectsId}/detail.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result && result.data) {
|
||||
if (result.data.status === 404) {
|
||||
if (window.location.pathname.includes('/invite')) {
|
||||
let inviteString = window.location.search && window.location.search.split('?invite=')[1];
|
||||
let data = inviteString && JSON.parse(Base64.decode(inviteString));
|
||||
const { project = {}, projectDetail = {} } = this.state
|
||||
this.setState({
|
||||
project: Object.assign(project, { author: { name: data.ownerName } }),
|
||||
projectDetail: Object.assign(projectDetail, { name: data.projectName })
|
||||
});
|
||||
} else {
|
||||
this.props.history.push('/nopage');
|
||||
}
|
||||
} else {
|
||||
this.setState({
|
||||
projectDetail: result.data,
|
||||
project_id: result.data.project_id,
|
||||
isManager: result.data.permission && (result.data.permission === "Manager" || result.data.permission === "Admin" || result.data.permission === "Owner"),
|
||||
isReporter: result.data.permission && result.data.permission === "Reporter",
|
||||
isDeveloper: result.data.permission && result.data.permission === "Developer",
|
||||
http_url: result.data.clone_url,
|
||||
praised: result.data.praised,
|
||||
watched: result.data.watched,
|
||||
watchers_count: result.data.watchers_count,
|
||||
praises_count: result.data.praises_count,
|
||||
forked_count: result.data.forked_count,
|
||||
defaultBranch: result.data.default_branch
|
||||
});
|
||||
// seo优化设置
|
||||
let keyWords=`${owner},${projectsId},${result.data.author.name},`;
|
||||
let title= `${owner}/${projectsId}${result.data.description?':'+result.data.description:''}`;
|
||||
setSeoMeta(keyWords,title,result.data.description,`/${owner}/${projectsId}`,owner,projectsId);
|
||||
}
|
||||
if (!data) {
|
||||
const url = `/${owner}/${projectsId}/detail.json`;
|
||||
const res = await axios.get(url)
|
||||
if (res.data) {
|
||||
data = res.data
|
||||
}
|
||||
}).catch((error) => { })
|
||||
}
|
||||
console.log('=============data==============')
|
||||
if (data) {
|
||||
if (data.status === 404) {
|
||||
if (window.location.pathname.includes('/invite')) {
|
||||
let inviteString = window.location.search && window.location.search.split('?invite=')[1];
|
||||
let inviteData = inviteString && JSON.parse(Base64.decode(inviteString));
|
||||
const { project = {}, projectDetail = {} } = this.state
|
||||
this.setState({
|
||||
project: Object.assign(project, { author: { name: inviteData.ownerName } }),
|
||||
projectDetail: Object.assign(projectDetail, { name: inviteData.projectName })
|
||||
});
|
||||
} else {
|
||||
this.props.history.push('/nopage');
|
||||
}
|
||||
} else {
|
||||
this.setState({
|
||||
projectDetail: data,
|
||||
project_id: data.project_id,
|
||||
isManager: data.permission && (data.permission === "Manager" || data.permission === "Admin" || data.permission === "Owner"),
|
||||
isReporter: data.permission && data.permission === "Reporter",
|
||||
isDeveloper: data.permission && data.permission === "Developer",
|
||||
http_url: data.clone_url,
|
||||
praised: data.praised,
|
||||
watched: data.watched,
|
||||
watchers_count: data.watchers_count,
|
||||
praises_count: data.praises_count,
|
||||
forked_count: data.forked_count,
|
||||
defaultBranch: data.default_branch
|
||||
});
|
||||
// seo优化设置
|
||||
let keyWords=`${owner},${projectsId},${data.author.name},`;
|
||||
let title= `${owner}/${projectsId}${data.description?':'+data.description:''}`;
|
||||
setSeoMeta(keyWords,title,data.description,`/${owner}/${projectsId}`,owner,projectsId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取动态导航栏菜单
|
||||
getBanner() {
|
||||
async getBanner(data) {
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
const url = `/${owner}/${projectsId}/menu_list.json`;
|
||||
axios.get(url).then(result => {
|
||||
if (result) {
|
||||
this.setState({
|
||||
bannerList: result.data
|
||||
})
|
||||
if (!data) {
|
||||
const url = `/${owner}/${projectsId}/menu_list.json`;
|
||||
const res = await axios.get(url)
|
||||
if (res.data) {
|
||||
data = res.data
|
||||
}
|
||||
}).catch(error => { })
|
||||
}
|
||||
|
||||
if (data) {
|
||||
this.setState({
|
||||
bannerList: data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 关注和取消关注
|
||||
|
|
@ -877,4 +934,39 @@ class Detail extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default withRouter(Detail);
|
||||
const mapStateToProps = (state) => {
|
||||
const {
|
||||
projectBase,
|
||||
defaultDetail,
|
||||
projectMenu,
|
||||
} = state.projectReducer;
|
||||
return {
|
||||
projectBase,
|
||||
defaultDetail,
|
||||
projectMenu,
|
||||
};
|
||||
}
|
||||
|
||||
Detail.preFetch = ({ store, match, query }) => {
|
||||
return new Promise(async function(resolve, reject) {
|
||||
let { dispatch, getState } = store;
|
||||
// const { owner,projectsId } = match.params
|
||||
console.log(match.params)
|
||||
const promises = [
|
||||
dispatch(setProjectDetail(match.params)),
|
||||
dispatch(setProject(match.params)),
|
||||
dispatch(setProjectEntries({...match.params, branch: 'master'})),
|
||||
dispatch(setProjectMenuList(match.params)),
|
||||
dispatch(setProjectReadMe({...match.params, branch: 'master'}))
|
||||
|
||||
];
|
||||
const data = await Promise.all(promises);
|
||||
resolve({
|
||||
code: 200,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export default withRouter(connect(
|
||||
mapStateToProps
|
||||
)(Detail));
|
||||
|
|
@ -28,9 +28,9 @@ class IndexItem extends Component {
|
|||
<img className="p-r-photo" alt="" src={item.author && item.author.image_url} ></img>
|
||||
</a>
|
||||
:
|
||||
<Link to={`/${item.author && item.author.login}`} className="show-user-link">
|
||||
<a href="javascript:void(0)" onClick={() => { window.location.href = `/${i.author && i.author.login}/${i.identifier}` }} className="show-user-link">
|
||||
<img className="p-r-photo" alt="" src={getImageUrl(`/${item.author && item.author.image_url}`)} ></img>
|
||||
</Link>
|
||||
</a>
|
||||
}
|
||||
<div className="p-r-Infos">
|
||||
<div className="p-r-name">
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ function Index() {
|
|||
}
|
||||
<div className="itemTitle">
|
||||
<div className="item-title-infos">
|
||||
<Link to={`/${i.author && i.author.login}/${i.identifier}`} className="infotitle task-hide">{i.author && i.author.name}/{i.name}</Link>
|
||||
<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>
|
||||
{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>
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ const ProjectDetail = Loadable({
|
|||
});
|
||||
export default withRouter(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
|
||||
((props)=>{
|
||||
|
||||
console.log(456)
|
||||
|
||||
return (
|
||||
<div className="newMain">
|
||||
<Switch>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import Loadable from "react-loadable";
|
||||
import Loading from "../../Loading";
|
||||
|
|
@ -6,41 +6,99 @@ import { withRouter } from "react-router";
|
|||
import { SnackbarHOC } from "educoder";
|
||||
import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC";
|
||||
import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC";
|
||||
import ProjectDetail from "../Main/Detail";
|
||||
const Infos = Loadable({
|
||||
loader: () => import("./Infos"),
|
||||
loading: Loading,
|
||||
});
|
||||
// forge项目详情
|
||||
const ProjectDetail = Loadable({
|
||||
loader: () => import("../Main/Detail"),
|
||||
loading: Loading,
|
||||
});
|
||||
export default withRouter(
|
||||
(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC((props) => {
|
||||
// // forge项目详情
|
||||
// const ProjectDetail = Loadable({
|
||||
// loader: () => import("../Main/Detail"),
|
||||
// loading: Loading,
|
||||
// });
|
||||
|
||||
class DetailTop extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
getProject = (num) => {
|
||||
const { projectsId, owner } = this.props.match.params;
|
||||
const url = `https://www.gitlink.org.cn/${owner}/${projectsId}/simple.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result && result.data) {
|
||||
this.setState({
|
||||
project: result.data,
|
||||
open_devops: result.data.open_devops,
|
||||
platform: result.data.platform && result.data.platform !== 'educoder'
|
||||
})
|
||||
if (result.data.type !== 0 && result.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({
|
||||
mirror_status:1
|
||||
})
|
||||
} else if (result.data.mirror_status === 2) {
|
||||
this.setState({
|
||||
mirror_status:2,
|
||||
firstSync: false
|
||||
})
|
||||
this.deleteProjectBack();
|
||||
} else {
|
||||
this.setState({
|
||||
firstSync: false,
|
||||
secondSync: false,
|
||||
mirror_status:0
|
||||
})
|
||||
this.getBanner();
|
||||
this.getDetail();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
// 个人中心新增的二级目录都需在此添加一次。将项目放组织和个人名下后,此处根据二级目录作判断,
|
||||
let secondRouter = '';
|
||||
if (props.location.pathname) {
|
||||
secondRouter = props.location.pathname.split('/')[2];
|
||||
if (this.props.location.pathname) {
|
||||
secondRouter = this.props.location.pathname.split('/')[2];
|
||||
}
|
||||
|
||||
let userRouterArr = ['statistics', 'projects', 'notice', 'devops', 'organizes', 'info', 'following', 'followers', 'password' , "general", "blockchain"];
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
|
||||
{secondRouter && (!userRouterArr.includes(secondRouter)) ? <Route
|
||||
path="/:owner/:projectsId"
|
||||
render={(p) => (
|
||||
<ProjectDetail {...props} {...p} />
|
||||
<ProjectDetail {...this.props} {...p} />
|
||||
)}
|
||||
></Route> : <Route
|
||||
path="/:username"
|
||||
render={(p) => (
|
||||
<Infos {...props} {...p} />
|
||||
<Infos {...this.props} {...p} />
|
||||
)}
|
||||
></Route>}
|
||||
|
||||
</Switch>
|
||||
)
|
||||
}))))
|
||||
)
|
||||
}
|
||||
}
|
||||
const user = (CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(DetailTop))))
|
||||
|
||||
user.preFetch = ProjectDetail.preFetch
|
||||
|
||||
export default withRouter(user)
|
||||
13
src/index.js
13
src/index.js
|
|
@ -7,20 +7,27 @@ import './index.css';
|
|||
import App from './App';
|
||||
import { configureUrlQuery } from 'react-url-query';
|
||||
import history from './history';
|
||||
import configureStore from './redux/stores/configureStore';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
configureUrlQuery({ history });
|
||||
const store = configureStore();
|
||||
|
||||
window.__useKindEditor = false;
|
||||
|
||||
|
||||
|
||||
const render = (Component) => {
|
||||
ReactDOM.render(
|
||||
<AppContainer >
|
||||
ReactDOM.hydrate(
|
||||
<AppContainer>
|
||||
{/* <Component /> */}
|
||||
<Provider store={store}>
|
||||
|
||||
<BrowserRouter basename='/'>
|
||||
<Route path={`/`} component={App}></Route>
|
||||
<Route path='/' component={App}></Route>
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
|
||||
</AppContainer>,
|
||||
document.getElementById('root')
|
||||
)
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ class LoginDialog extends Component {
|
|||
this.setState({
|
||||
isphone: flag,
|
||||
//查询第三方登录信息
|
||||
settings: JSON.parse(localStorage.getItem("chromesetting")),
|
||||
settings: JSON.parse(localStorage.getItem("chromesetting") || '{}'),
|
||||
})
|
||||
|
||||
if (this.props.isRender != undefined) {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ export function TPMIndexHOC(WrappedComponent) {
|
|||
window.removeEventListener('keyup', this.keyupListener)
|
||||
}
|
||||
componentWillMount() {
|
||||
this.fetchUsers();
|
||||
// console.log(123)
|
||||
// this.fetchUsers();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
|
@ -165,7 +166,7 @@ export function TPMIndexHOC(WrappedComponent) {
|
|||
publicNav:false
|
||||
})
|
||||
}
|
||||
let url = `/users/get_user_info.json`;
|
||||
let url = `/api/users/get_user_info.json`;
|
||||
axios.get(url).then((response) => {
|
||||
if (response && response.data) {
|
||||
this.initCommonState(response.data)
|
||||
|
|
@ -317,7 +318,7 @@ export function TPMIndexHOC(WrappedComponent) {
|
|||
<div className="newContainer newContainers">
|
||||
{!publicNav && <div style={{height:"58px"}}></div> }
|
||||
{
|
||||
current_user &&
|
||||
// current_user &&
|
||||
<WrappedComponent initCommonState={(user) => this.initCommonState(user)}
|
||||
{...this.props} {...this.state} {...common} >
|
||||
</WrappedComponent>
|
||||
|
|
|
|||
|
|
@ -106,7 +106,13 @@ const types = {
|
|||
IS_SHOW_WXCODE_TEST_CASES: 'IS_SHOW_WXCODE_TEST_CASES',
|
||||
SHOW_WX_CODE_LOADING: 'SHOW_WX_CODE_LOADING',
|
||||
SHOW_WX_CODE_DIALOG: 'SHOW_WX_CODE_DIALOG',
|
||||
SET_GOLD_AND_EXPERIENCE: 'SET_GOLD_AND_EXPERIENCE'
|
||||
SET_GOLD_AND_EXPERIENCE: 'SET_GOLD_AND_EXPERIENCE',
|
||||
/** 服务端渲染 */
|
||||
GET_PROJECT_BASE: 'GET_PROJECT_BASE',
|
||||
GET_PROJECT_DETAIL: 'GET_PROJECT_DETAIL',
|
||||
GET_PROJECT_ENTRIES: 'GET_PROJECT_ENTRIES',
|
||||
GET_PROJECT_MENU: 'GET_PROJECT_MENU',
|
||||
GET_PROJECT_README: 'GET_PROJECT_README',
|
||||
}
|
||||
|
||||
export default types;
|
||||
|
|
|
|||
|
|
@ -126,6 +126,11 @@ import {
|
|||
changeWXCodeEvaluateLoading,
|
||||
changeWXCodeEvaluateDialog
|
||||
} from './wxCode';
|
||||
|
||||
import {
|
||||
setProject,
|
||||
} from './server.js';
|
||||
|
||||
export default {
|
||||
toggleTodo,
|
||||
getOJList,
|
||||
|
|
@ -223,5 +228,7 @@ export default {
|
|||
evaluateWxCode,
|
||||
showWXCodeTextCase,
|
||||
changeWXCodeEvaluateLoading,
|
||||
changeWXCodeEvaluateDialog
|
||||
changeWXCodeEvaluateDialog,
|
||||
// 服务端渲染
|
||||
setProject
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import types from './actionTypes';
|
||||
import { getProjectFunc, getProjectDetailFunc, getProjectEntriesFunc, getBannerFunc, getProjectReadMe } from '../../services/project'
|
||||
|
||||
|
||||
// 获取项目信息
|
||||
export const setProject = ({ owner,projectsId }) => {
|
||||
return (dispatch) => {
|
||||
return getProjectFunc(owner, projectsId).then(res => {
|
||||
dispatch({
|
||||
type: types.GET_PROJECT_BASE,
|
||||
payload: res.data
|
||||
});
|
||||
return res.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 获取项目详情信息
|
||||
export const setProjectDetail = ({ owner,projectsId }) => {
|
||||
return (dispatch) => {
|
||||
return getProjectDetailFunc(owner, projectsId).then(res => {
|
||||
dispatch({
|
||||
type: types.GET_PROJECT_DETAIL,
|
||||
payload: res.data
|
||||
});
|
||||
return res.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 获取文件列表
|
||||
export const setProjectEntries = ({ owner,projectsId, branch }) => {
|
||||
return (dispatch) => {
|
||||
return getProjectEntriesFunc(owner, projectsId, branch).then(res => {
|
||||
dispatch({
|
||||
type: types.GET_PROJECT_ENTRIES,
|
||||
payload: res.data
|
||||
});
|
||||
return res.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 获取banner
|
||||
export const setProjectMenuList = ({ owner,projectsId }) => {
|
||||
return (dispatch) => {
|
||||
return getBannerFunc(owner, projectsId).then(res => {
|
||||
dispatch({
|
||||
type: types.GET_PROJECT_MENU,
|
||||
payload: res.data
|
||||
});
|
||||
return res.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 获取readMe
|
||||
export const setProjectReadMe = ({ owner,projectsId, branch }) => {
|
||||
return (dispatch) => {
|
||||
return getProjectReadMe(owner, projectsId, branch).then(res => {
|
||||
dispatch({
|
||||
type: types.GET_PROJECT_README,
|
||||
payload: res.data
|
||||
});
|
||||
return res.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -18,6 +18,7 @@ import commentReducer from './commentReducer';
|
|||
import tpiReducer from './tpiReducer';
|
||||
import staticReducer from './staticReducer';
|
||||
import wxcodeReducer from './wxcodeReducer';
|
||||
import projectReducer from './projectReducer'
|
||||
|
||||
export default combineReducers({
|
||||
testReducer,
|
||||
|
|
@ -30,5 +31,6 @@ export default combineReducers({
|
|||
commentReducer,
|
||||
tpiReducer,
|
||||
staticReducer,
|
||||
wxcodeReducer
|
||||
wxcodeReducer,
|
||||
projectReducer
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
import types from "../actions/actionTypes";
|
||||
|
||||
const initialState = {
|
||||
defaultDetail: '', // 当前项目基本信息
|
||||
projectBase: '', // 当前项目详情
|
||||
projectEntries: '', // 当前文件列表
|
||||
projectMenu: '', // 当前menu
|
||||
projectReadMe: '', // 当前readme
|
||||
};
|
||||
|
||||
const projectReducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case types.GET_PROJECT_DETAIL:
|
||||
return {
|
||||
...state,
|
||||
defaultDetail: action.payload
|
||||
}
|
||||
case types.GET_PROJECT_BASE:
|
||||
return {
|
||||
...state,
|
||||
projectBase: action.payload
|
||||
}
|
||||
case types.GET_PROJECT_ENTRIES:
|
||||
return {
|
||||
...state,
|
||||
projectEntries: action.payload
|
||||
}
|
||||
case types.GET_PROJECT_MENU:
|
||||
return {
|
||||
...state,
|
||||
projectMenu: action.payload
|
||||
}
|
||||
case types.GET_PROJECT_README:
|
||||
return {
|
||||
...state,
|
||||
projectReadMe: action.payload
|
||||
}
|
||||
default:
|
||||
return {
|
||||
...state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default projectReducer;
|
||||
export {
|
||||
projectReducer
|
||||
};
|
||||
|
|
@ -12,7 +12,13 @@ import rootReducer from '../reducers';
|
|||
|
||||
const configureStore = () => createStore(
|
||||
rootReducer,
|
||||
window.__initState__,
|
||||
applyMiddleware(thunk)
|
||||
);
|
||||
|
||||
export default configureStore;
|
||||
|
||||
export const serverStore = ()=>{
|
||||
return createStore(rootReducer, applyMiddleware(thunk));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import axios from 'axios';
|
||||
|
||||
const baseUrl = 'https://www.gitlink.org.cn/api'
|
||||
|
||||
//
|
||||
export async function getProjectFunc (owner, projectsId) {
|
||||
console.log('4444444444444444444444444')
|
||||
const url = `${baseUrl}/${owner}/${projectsId}/simple.json`;
|
||||
return axios.get(url);
|
||||
}
|
||||
|
||||
export async function getProjectDetailFunc (owner, projectsId) {
|
||||
const url = `${baseUrl}/${owner}/${projectsId}/detail.json`;
|
||||
return axios.get(url);
|
||||
}
|
||||
|
||||
export async function getProjectEntriesFunc (owner, projectsId, branch) {
|
||||
const url = `${baseUrl}/${owner}/${projectsId}/entries.json`;
|
||||
return axios.get(url, {params: { ref: branch }});
|
||||
}
|
||||
|
||||
export async function getBannerFunc (owner, projectsId) {
|
||||
const url = `${baseUrl}/${owner}/${projectsId}/menu_list.json`;
|
||||
return axios.get(url);
|
||||
}
|
||||
|
||||
export async function getProjectReadMe (owner, projectsId, branch) {
|
||||
const url = `${baseUrl}/${owner}/${projectsId}/readme.json`;
|
||||
return axios.get(url, {params: { ref: branch }});
|
||||
}
|
||||
Loading…
Reference in New Issue