This commit is contained in:
黄心宇 2024-01-05 15:01:16 +08:00
parent cb21d82b75
commit 96475ab739
29 changed files with 769 additions and 212 deletions

View File

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

View File

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

View File

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

68
package-lock.json generated
View File

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

View File

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

View File

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

View File

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

33
server/service.js Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -41,6 +41,9 @@ const ProjectDetail = Loadable({
});
export default withRouter(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
((props)=>{
console.log(456)
return (
<div className="newMain">
<Switch>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

30
src/services/project.js Normal file
View File

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