softbot联调

This commit is contained in:
谢思 2023-01-11 09:21:03 +08:00
parent f7033a33e4
commit d15e2d1c84
36 changed files with 2591 additions and 1476 deletions

2378
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2340181 */
src: url('iconfont.woff2?t=1653550272457') format('woff2'),
url('iconfont.woff?t=1653550272457') format('woff'),
url('iconfont.ttf?t=1653550272457') format('truetype');
src: url('iconfont.woff2?t=1673243764843') format('woff2'),
url('iconfont.woff?t=1673243764843') format('woff'),
url('iconfont.ttf?t=1673243764843') format('truetype');
}
.iconfont {
@ -13,6 +13,42 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-yuyue-lishi-shijian:before {
content: "\e93f";
}
.icon-a-duobianxing1:before {
content: "\e93c";
}
.icon-a-duobianxing2:before {
content: "\e93d";
}
.icon-sousuo5:before {
content: "\e93e";
}
.icon-baogaoppt:before {
content: "\e93b";
}
.icon-gailan2:before {
content: "\e93a";
}
.icon-bianji7:before {
content: "\e939";
}
.icon-ROBOT:before {
content: "\e937";
}
.icon-a-zu1404:before {
content: "\e938";
}
.icon-tuichuicon:before {
content: "\e936";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,69 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "6978097",
"name": "预约-历史-时间",
"font_class": "yuyue-lishi-shijian",
"unicode": "e93f",
"unicode_decimal": 59711
},
{
"icon_id": "31659662",
"name": "多边形 1",
"font_class": "a-duobianxing1",
"unicode": "e93c",
"unicode_decimal": 59708
},
{
"icon_id": "31659664",
"name": "多边形 2",
"font_class": "a-duobianxing2",
"unicode": "e93d",
"unicode_decimal": 59709
},
{
"icon_id": "31659665",
"name": "搜索",
"font_class": "sousuo5",
"unicode": "e93e",
"unicode_decimal": 59710
},
{
"icon_id": "31424249",
"name": "报告ppt",
"font_class": "baogaoppt",
"unicode": "e93b",
"unicode_decimal": 59707
},
{
"icon_id": "31318120",
"name": "概览",
"font_class": "gailan2",
"unicode": "e93a",
"unicode_decimal": 59706
},
{
"icon_id": "31275425",
"name": "编辑",
"font_class": "bianji7",
"unicode": "e939",
"unicode_decimal": 59705
},
{
"icon_id": "30382389",
"name": "ROBOT",
"font_class": "ROBOT",
"unicode": "e937",
"unicode_decimal": 59703
},
{
"icon_id": "30382697",
"name": "组 1404",
"font_class": "a-zu1404",
"unicode": "e938",
"unicode_decimal": 59704
},
{
"icon_id": "29934961",
"name": "退出icon",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -12,7 +12,7 @@
<meta property="og:site_name" content="GitLink" />
<meta property="og:description" content="GitLink,新一代开源创新服务平台 分布式协作开发 一站式过程管理 高效流水线运维 多层次代码分析 多维度用户画像 分布式协作开发 基于Git打造分布式代码托管环境" />
<meta name="theme-color" content="#000000">
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" /> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link href="https://gw.alipayobjects.com/os/lib/alipay/alex/2.0.19/bundle/alex.all.global.min.css" rel="stylesheet"/>
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont.css">

View File

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> -->
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--

View File

@ -1,39 +1,121 @@
import { Button, Checkbox, Radio, Select } from "antd";
import React from "react";
import { Button, Checkbox, message, Radio, Select, Switch } from "antd";
import axios from "axios";
import moment from "moment";
import React, { useEffect } from "react";
import { useState } from "react";
import { Link } from "react-router-dom";
import { getInstallBot, updateInstallBot } from "../../../../softbot/api";
import { getImageUrl } from 'educoder';
import './index.scss';
function DispositionDetail(props){
const {match:{params:{id}}, current_user} = props;
const [checkValue, setCheckValue] = useState(0);
const [selectValue, setSelectValue] = useState([]);
const [options, setOptions] = useState(['仓库1', '仓库2仓库2', '仓库仓库2仓库2仓库2仓库2仓库2', '仓库4', '仓库5']);
const filterOption = options.filter(item=>!selectValue.includes(item));
const [botDetail, setBotDetail] = useState(undefined);
const [options, setOptions] = useState(undefined);
const [filterOption, setFilterOption] = useState([]);
// bot
const [botState, setBotState] = useState(true);
// const filterOption = options.filter(item=>!selectValue.includes(item));
// bot
useEffect(()=>{
getInstallBot({
user_id: current_user && current_user.user_id,
bot_id: id
}).then(res=>{
if(res && res.code === 200){
const {state} = res.data;
setBotState(state);
setBotDetail(res.data);
}
})
//
current_user && axios.get(`/users/${current_user.login}/projects.json`,{
params:{
limit: 1000,
page: 1,
category:"manage"
}
}).then(result=>{
if(result && result.data){
setOptions(result.data.projects);
setFilterOption(result.data.projects);
}
}).catch(error=>{
console.log(error);
})
}, [])
// selectValue
useEffect(()=>{
const ids = selectValue.map(item=>{return item.id});
options && setFilterOption(options.filter(item=>!ids.includes(item.id)));
}, [selectValue])
//
useEffect(()=>{
if(botDetail && options){
if(botDetail.store_id_list.length === options.length){
setCheckValue(0);
}else{
setCheckValue(1);
//
const {store_id_list} = botDetail;
const allStoreId = options.map((item)=>{return item.id});
let newMap = selectValue;
store_id_list.map(item=>{
if(allStoreId.includes(item)){
newMap = newMap.concat(options.filter(i=>{return i.id === item})[0]);
}
})
setSelectValue(newMap);
}
}
}, [options, botDetail])
function selectChange(e){
let newMap = selectValue;
newMap = newMap.concat(e);
newMap = newMap.concat(options.filter(i=>{return i.id === e})[0]);
setSelectValue(newMap);
}
function deleteSelect(e){
let newMap = selectValue;
newMap = newMap.filter(item=>{return item !== e});
newMap = newMap.filter(item=>{return item.id !== e.id});
setSelectValue(newMap);
}
function updateInsBot(){
updateInstallBot({
bot_id: id,
password: "",
state: botState ? 1 : 0,
store_list: checkValue ? selectValue.map(item=>{return item.id}) : options.map(item=>{return item.id}),
user_id: current_user && current_user.user_id
}).then(res=>{
if(res && res.code === 200){
message.success('更改成功');
}
})
}
return <div className="dispositionDetailBox">
<div className="oneLine mb30">
<div className="oneLine">
<img src="" alt="" className="botImg imgBox"/>
{botDetail && <img src={getImageUrl(botDetail.logo)} alt="" className="botImg imgBox"/>}
<div className="ml40 font-16">
<div className="font-22">Bot名称</div>
<span className="mr30 color88">开发者姓名</span>
<span className="color88">2022-6-23</span>
<div className="font-22">{botDetail && botDetail.market_name}</div>
<span className="mr30 color88">{botDetail && botDetail.register_id}</span>
<span className="color88">{botDetail && botDetail.market_time && moment(botDetail.market_time).format('YYYY-MM-DD hh:mm:ss')}</span>
</div>
</div>
<Button style={{width: '53px', padding: '0'}} className="grayBorBut"><Link to={`/settings/dispositionBot`}>返回</Link></Button>
</div>
<div className="mb10"><Checkbox className="greenCol font-16">代码库只读权限</Checkbox></div>
<div className="mb20"><Checkbox className="greenCol font-16">合并请求(PR)读写权限</Checkbox></div>
{botDetail && <div className="mb10"><Checkbox className="greenCol font-16" checked={botDetail.limit_vo.juris_diction_code !== 2}>代码库{botDetail.limit_vo.juris_diction_code === 2 ? '无' : botDetail.limit_vo.juris_diction_code === 1 ? '读写' : '只读'}权限</Checkbox></div>}
{botDetail && <div className="mb20"><Checkbox className="greenCol font-16" checked={botDetail.limit_vo.juris_diction_pr !== 2}>合并请求(PR){botDetail.limit_vo.juris_diction_pr === 2 ? '无' : botDetail.limit_vo.juris_diction_pr === 1 ? '读写' : '只读'}权限</Checkbox></div>}
<div className="detailTil font-16">更改安装位置</div>
<div>
<Radio.Group onChange={(e)=>{setCheckValue(e.target.value)}} value={checkValue}>
@ -41,38 +123,45 @@ function DispositionDetail(props){
<Radio value={1} className="radioBox mt15 font-16">安装到指定仓库<br/><span className="font-15 radioBoxTip">请至少选择一个仓库</span></Radio>
</Radio.Group>
{checkValue === 1 && <Select
placeholder="请输入仓库名称"
value={selectValue}
placeholder="请选择仓库名称"
value={selectValue.map(item=>{return item.id})}
onChange={selectChange}
className="radioBox selectBox"
>
{filterOption.map(item=>(<Select.Option key={item} value={item}>{item}</Select.Option>))}
{filterOption.map(item=>(<Select.Option key={item.id} value={item.id}>{item.name}</Select.Option>))}
</Select>}
{selectValue.map((item, index)=>{return <div key={index} className="selectValueBox font-14"><i className="iconfont icon-daimakuicon1 font-14 mr5"></i><span className="selectValue">{item}</span><i className="iconfont icon-guanbi font-12 close ml30" onClick={()=>{deleteSelect(item)}}></i></div>})}
{checkValue === 1 && selectValue.map((item, index)=>{return <div key={index} className="selectValueBox font-14"><i className="iconfont icon-daimakuicon1 font-14 mr5"></i><span className="selectValue">{item.name}</span><i className="iconfont icon-guanbi font-12 close ml30" onClick={()=>{deleteSelect(item)}}></i></div>})}
</div>
<div className="detailTil font-16 mt30">更改Bot状态</div>
<div className="disBotItem">
<div className="detailTil font-16 mt30 mb10">更改Bot状态</div>
{/* {botDetail && botDetail.state === 1 && <div className="disBotItem">
<div>
<div className="font-15">挂起</div>
<span className='changeStatusTip'>暂停停止使用该bot阻塞该bot拥有的仓库访问权限</span>
</div>
<Button className="dangerBorBut" style={{width: '88px', height: '36px'}}>挂起</Button>
</div>
<div className="disBotItem">
</div>}
{botDetail && botDetail.state === 0 && <div className="disBotItem">
<div>
<div className="font-15">启用</div>
<span className='changeStatusTip'>开始使用该Bot授予该Bot所需的仓库访问权限</span>
</div>
<Button className="themeCorBorBut" style={{width: '88px', height: '36px'}}>启用</Button>
</div>} */}
<div className="ml25">
{botDetail && <Switch defaultChecked = {botDetail.state} onChange={(checked)=>{setBotState(checked)}}/>}
<div className="mt10">
<div className="font-15">{botState ? '启用' : '挂起'}</div>
<span className='changeStatusTip'>{botState ? '开始使用该Bot授予该Bot所需的仓库访问权限' : '暂停停止使用该bot阻塞该bot拥有的仓库访问权限'}</span>
</div>
</div>
<div className="disBotItem">
{/* <div className="disBotItem">
<div>
<div className="font-15">卸载</div>
<span className='changeStatusTip'>将该bot从仓库中卸载回收所有分配给该bot的权限将其从安装列表中删除</span>
</div>
<Button className="dangerBorBut" style={{width: '88px', height: '36px'}}>卸载</Button>
</div>
<Button type="primary" style={{width: '100px', height: '36px'}} className="mt30">保存</Button>
</div> */}
<Button type="primary" style={{width: '100px', height: '36px'}} className="mt30" onClick={updateInsBot}>保存</Button>
</div>
}
export default DispositionDetail;

View File

@ -1,25 +1,80 @@
import React, { useState } from "react";
import { Button } from "antd";
import React, { useEffect, useState } from "react";
import { Button, message, Modal } from "antd";
import { Link } from "react-router-dom";
import { getImageUrl } from 'educoder';
import nullBot from '../../../../softbot/image/notBot.png';
import { getAllInstallBots, deleteInstallBot } from "../../../../softbot/api";
import './index.scss';
// bot
function DispositionBot(props){
const [botList, setBotList] = useState([{botName: '此处为名称标题内容', status: '0', id: '0'}, {botName: '此处为名称标题内容', status: '1', id: '1'}]);
const {current_user} = props;
const [botList, setBotList] = useState(undefined);
const [delBotId, setDelBotId] = useState(undefined);
const [visible, setVisible] = useState(false);
const [reload, setReload] = useState(undefined);
useEffect(()=>{
getAllInstallBots({
"user_id": current_user && current_user.user_id
}).then(res=>{
if(res && res.code === 200){
setBotList(res.data.install_bots);
}
})
}, [reload])
function delInstallBot(){
deleteInstallBot({
user_id: current_user && current_user.user_id,
bot_id: delBotId,
password: ""
}).then(res=>{
if(res && res.code === 200){
message.success('卸载成功');
setVisible(false);
setReload(Math.random());
}
})
}
return <div>
<div className="dispositionHead font-18">Bot配置</div>
{/* bot列表显示区域 */}
{botList.length > 0 ? <div className="setBotListBox">
{botList && (botList.length > 0 ? <div className="setBotListBox">
{botList.map((item, index)=>{return <div className="disBotItem" key={index}>
<div>
<img src="" alt="" className="imgBox mr20"/>
<span className="font-15">{item.botName}</span>
<span className={`statusBox font-12 ml10 ${item.status === '0' ? 'active' : ''}`}>{item.status === '0' ? '启用' : '挂起'}</span>
<img src={getImageUrl(item.logo)} alt="" className="imgBox mr20"/>
<span className="font-15">{item.bot_name}</span>
<span className={`statusBox font-12 ml10 ${item.state === '0' ? '' : 'active'}`}>{item.state === '0' ? '挂起' : '启用'}</span>
</div>
<div>
<Button className="themeCorBorBut" style={{width: '68px', height: '36px'}}><Link to={`/settings/dispositionBot/${item.bot_id}`}>配置</Link></Button>
<Button className="dangerBorBut ml20" style={{width: '68px', height: '36px'}} onClick={()=>{setDelBotId(item.bot_id);setVisible(true)}}>卸载</Button>
</div>
<Button className="themeCorBorBut" style={{width: '68px', height: '36px'}}><Link to={`/settings/dispositionBot/${item.id}`}>配置</Link></Button>
</div>})}
</div> : <div className="font-16 setBotListBox">欢迎使用Bot! Bot可以帮助项目贡献者处理繁杂的项目任务比如关闭疑修合并请求在使用之前请先注册一个Bot</div>}
</div> : <div className="nullBotsBox mt80">
<img src={nullBot} alt="" width={62}/>
<p className="font-18 showBigTip">您当前暂未安装任何Bot</p>
<div className="showTip font-14">Bot可以帮助项目贡献者处理繁杂的项目任务比如关闭疑修合并请求等以节约时间精力提升开发效率快去市场中挑选一个适合您项目的Bot吧!</div>
<div className="borTip"></div>
<Button type="primary" style={{width: '112px', height: '36px', padding: 0}}><Link to={'/softbot'}>去Bot市场逛逛</Link></Button>
</div>)}
<Modal
className="f8HeadModal"
width="485px"
title="卸载Bot"
visible={visible}
maskClosable={false}
footer={[
<Button onClick={()=>{setVisible(false)}} className="mr30 grayBorBut whiteBackBut" style={{width:"104px", height: '36px'}}>取消</Button>,
<Button className="redFontBut grayBorBut whiteBackBut" style={{width:"104px", height: '36px'}} onClick={delInstallBot}>确认卸载</Button>
]}
onCancel={()=>{setVisible(false)}}
>
<div className="font-16 titleTip mt20"><span className="circleRed font-18">!</span>您确定要卸载此Bot吗</div>
<div className="deleteTip">卸载后将回收所有分配给该bot的权限</div>
</Modal>
</div>
}
export default DispositionBot;

View File

@ -32,7 +32,6 @@
.imgBox{
width: 44px;
height: 44px;
background-color: yellow;
border-radius: 50%;
}
.dispositionDetailBox{
@ -101,4 +100,20 @@
}
}
.changeStatusTip{color:#99a2af;}
}
.nullBotsBox{
border-radius: 4px 4px 0px 0px;
text-align: center;
padding: 25px 158px 65px;
.showBigTip{
color:#333333;
margin-top: 16px;
margin-bottom: 22px !important;
}
.showTip{color: #666;}
.borTip{
width: 82%;
margin: 20px auto 18px;
border-top: 1px solid rgba(90, 117, 193, 0.23)
}
}

View File

@ -0,0 +1,107 @@
import React ,{useEffect, useRef, useState} from 'react';
import { Modal , message } from 'antd';
import Cropper from 'react-cropper';
import 'cropperjs/dist/cropper.css';
import axios from 'axios';
import '../../../../../../forge/users/Avatar/Index.scss';
function Index({onCancel,avatarImg,id, botDetail}){
const [ avatarPhoto , setAvatarPhoto ] = useState(avatarImg);
useEffect(()=>{
if(avatarImg){
setAvatarPhoto(avatarImg);
}
},[avatarImg])
const cropper = useRef();
const saveAvatar = async () => {
const imgUrl = cropper.current.cropper.getCroppedCanvas().toDataURL("image/png");
if (!imgUrl) {
message.info('请先上传图片');
}
const params = {
...botDetail,
bot_id: parseInt(id)
}
console.log('params', params);
registerUpdateBot(params).then(res=>{
if(res && res.code === 200){
message.success("更改成功");
setReload(Math.random());
}
})
}
function onChange(e){
let files;
if (e.dataTransfer) {
files = e.dataTransfer.files;
} else if (e.target) {
files = e.target.files;
}
if (!files || (files && files.length===0)) {
return;
}
const file = files[0];
if (!/^image\/\w+/.test(file.type)) {
message.info('请选择一个图片格式的文件');
return;
}
if (file.size > 2 * 1024 * 1024) {
message.info('仅支持文件大小小于2M的文件');
return;
}
const reader = new FileReader();
reader.onload = () => {
if(reader.result){
setAvatarPhoto(reader.result);
}
};
reader.readAsDataURL(files[0]);
}
return(
<Modal
visible={true}
width="638px"
footer={null}
centered
maskClosable={false}
title="修改头像"
onCancel={()=>onCancel(false)}
className="avatarBox"
>
<div className="avatarDiv">
<div>
<Cropper
style={{ height: 320, width: 320 }}
src={avatarPhoto}
guides={false}
preview="#updateAvatarImg"
ref={cropper}
aspectRatio={1}
/>
{/* <span className={"tips"}>仅支持JPG、GIF、PNG且文件小于2M</span> */}
</div>
<div className="previewBox">
<div className={"previewImg"} id="updateAvatarImg"></div>
<div className="uploadBtn">
<label className={"uploadButton"} id="uploadBtn" htmlFor="inputImage">
<input type="file" className="sr-only" id="inputImage" name="file" accept="image/*" style={{ display: "none" }} onChange={onChange}></input>
点击上传
</label>
<a onClick={saveAvatar}>保存头像</a>
</div>
</div>
</div>
</Modal>
)
}
export default Index;

View File

@ -1,23 +1,36 @@
import { AutoComplete, Button, Modal } from "antd";
import { AutoComplete, Button, message, Modal } from "antd";
import React from "react";
import { useState, useEffect } from "react";
import { getImageUrl } from 'educoder';
import './index.scss';
import axios from "axios";
import { Link } from "react-router-dom";
import { deleteBot, transferBot, registerUpdateBot, downMarket, getMarketBotById, cancelTransferBot } from "../../../../../../softbot/api";
const { Option } = AutoComplete;
// Bot
function AdvancedInformation(props){
const {match} = props;
const {params:{id}} = match;
const {match, current_user, match:{params:{id}}, botDetail, setReload} = props;
const [ visibleMakeOver, setVisibleMakeOver] = useState(false);
const [ newId , setNewId] = useState(undefined);
const [ source , setSource ] = useState(undefined);
const [ searchKey , setSearchKey ] = useState(undefined);
// 012bot
// bot012
const [ type, setType] = useState(undefined);
const [ visibleDelete, setVisibleDelete] = useState(false);
// bot
const [makeOverErrortTip, setMakeOverErrortTip] = useState(undefined);
//
const [isMarket, setIsMarket] = useState(false);
//
const [marketReload, setMarketReload] = useState(undefined);
useEffect(()=>{
// bot
getMarketBotById({bot_id: id}).then(res=>{
res && setIsMarket(res.code === 200);
})
}, [marketReload])
useEffect(()=>{
getUserList();
@ -45,7 +58,7 @@ function AdvancedInformation(props){
//
function selectInputUser(e, option){
setNewId(option.props.login);
setNewId(option.props.value);
setSearchKey(option.props.name);
};
@ -77,17 +90,90 @@ function AdvancedInformation(props){
//
function makeOver(){
console.log('bei', newId);
setMakeOverErrortTip(undefined);
if(newId){
transferBot({
"user_id": current_user && current_user.user_id,
"user_name": current_user && current_user.username,
"bot_id": parseInt(id),
"transfer_to_user_id": parseInt(newId)
}).then(res=>{
if(res && res.code === 200){
message.success('操作成功');
setNewId(undefined);
setVisibleMakeOver(false);
setReload(Math.random());
}
})
}else{
setMakeOverErrortTip("请选择被转让者");
}
}
// ///Bot
function submitModal(){
if(type === '3'){
//
downMarket(parseInt(id), {}).then(res=>{
if(res && res.code === 200){
message.success('下架成功');
setVisibleDelete(false);
setMarketReload(Math.random());
}
})
}else if(type === '0'){
// bot
const params = {
user_id: current_user && current_user.user_id,
bot_id: parseInt(id)
}
deleteBot(params).then(res=>{
if(res && res.code === 200){
message.success('删除成功');
setVisibleDelete(false);
props.history.push("/settings/exploitBot/configuration");
}
})
}else{
// /bot
const params = {
...botDetail,
bot_id: parseInt(id),
is_public: type === '1' ? 1 : 0
}
registerUpdateBot(params).then(res=>{
if(res && res.code === 200){
setVisibleDelete(false);
message.success("更改成功");
setReload(Math.random());
}
})
}
}
function cancelTra(){
cancelTransferBot({
bot_id: parseInt(id),
user_id: current_user && current_user.user_id
}).then(res=>{
if(res && res.code === 200){
message.success("操作成功");
setReload(Math.random());
}
})
}
return <div className="advancedInformationBox">
<div className="informationHead pb15">高级选项</div>
{/* 提示:转让中状态 */}
{botDetail && botDetail.is_transfer_success === 2 && <div className="transferBotStatus mt15"><i className="iconfont icon-yuyue-lishi-shijian font-18 mr5 ml10"></i>此Bot正在等待转移至{botDetail.transfer_to_id}用户账号</div>}
<div className="disFlex itemBox">
<div className="font-15">
转让该Bot的所有权至其他用户
<p className="grayBox font-14">转让可能会推迟直到新的所有者批准转让</p>
</div>
<Button className="themeCorBorBut" style={{width:"88px", height: '36px', padding: '0'}} onClick={()=>{setVisibleMakeOver(true)}}>转让所有权</Button>
{botDetail && (botDetail.is_transfer_success !== 2 ? <Button className="themeCorBorBut" style={{width:"88px", height: '36px', padding: '0'}} onClick={()=>{setVisibleMakeOver(true)}}>转让所有权</Button> :
<Button className="themeCorBorBut" style={{width:"88px", height: '36px', padding: '0'}} onClick={cancelTra}>取消转让</Button>)}
</div>
<div className="disFlex itemBox">
<div className="font-15">
@ -96,14 +182,14 @@ function AdvancedInformation(props){
</div>
<Button className="dangerBorBut" style={{width:"88px", height: '36px', padding: '0'}} onClick={()=>{setType('0');setVisibleDelete(true)}}>删除Bot</Button>
</div>
<div className="disFlex itemBox">
{botDetail && !botDetail.is_public && <div className="disFlex itemBox">
<div className="font-15">
私有Bot
<p className="grayBox font-14">目前您的bot将不能被其他用户安装</p>
</div>
<Button className="themeCorBorBut" style={{width:"88px", height: '36px', padding: '0'}} onClick={()=>{setType('1');setVisibleDelete(true)}}>公开此Bot</Button>
</div>
<div className="disFlex itemBox">
</div>}
{botDetail && !!botDetail.is_public && !isMarket && <div className="disFlex itemBox">
<div className="font-15">
公开Bot
<p className="grayBox font-14">目前您的Bot所有用户都能安装</p>
@ -112,17 +198,17 @@ function AdvancedInformation(props){
<Button type="primary" style={{width:"88px", height: '36px', padding: '0'}} className="mr20"><Link to={`/settings/exploitBot/configuration/${id}/advanced/putaway`}>上架市场</Link></Button>
<Button className="themeCorBorBut" style={{width:"88px", height: '36px', padding: '0'}} onClick={()=>{setType('2');setVisibleDelete(true)}}>私有此Bot</Button>
</div>
</div>
<div className="disFlex itemBox">
</div>}
{botDetail && !!botDetail.is_public && isMarket && <div className="disFlex itemBox">
<div className="font-15">
公开Bot
<p className="grayBox font-14">目前您的Bot所有用户都能安装</p>
</div>
<div>
<Button type="primary" style={{width:"88px", height: '36px', padding: '0'}} className="mr20">编辑</Button>
<Button className="themeCorBorBut" style={{width:"88px", height: '36px', padding: '0'}}>下架市场</Button>
<Button type="primary" style={{width:"88px", height: '36px', padding: '0'}} className="mr20"><Link to={`/settings/exploitBot/configuration/${id}/advanced/putaway/edit`}>编辑</Link></Button>
<Button className="themeCorBorBut" style={{width:"88px", height: '36px', padding: '0'}} onClick={()=>{setType('3');setVisibleDelete(true)}}>下架市场</Button>
</div>
</div>
</div>}
{/* 转让bot弹框 */}
<Modal
className="themeHeadModal"
@ -131,8 +217,9 @@ function AdvancedInformation(props){
visible={visibleMakeOver}
maskClosable={false}
footer={null}
onCancel={()=>{setVisibleMakeOver(false)}}>
onCancel={()=>{setVisibleMakeOver(false);setMakeOverErrortTip(undefined)}}>
<div className="font-15 mt5 mb10 makeOverTip">新的所有者账号</div>
{makeOverErrortTip && <div className="font-15 mt5 mb10 makeOverErrorTip">{makeOverErrortTip}</div>}
<AutoComplete
dataSource={source}
value={searchKey}
@ -144,21 +231,21 @@ function AdvancedInformation(props){
/>
<Button type="primary" onClick={makeOver} className="makeOverSubmit" style={{width:"104px", height: '36px'}}>确认转让</Button>
</Modal>
{/* 删除Bot弹框 */}
{/* 删除/公开/私有Bot弹框 */}
<Modal
className="f8HeadModal"
width="550px"
title={`${type === '0' ? '删除' : type === '1' ? '公开' : '私有'}Bot`}
title={`${type === '0' ? '删除' : type === '1' ? '公开' : type === '2' ? '私有' : '下架'}Bot`}
visible={visibleDelete}
maskClosable={false}
footer={[
<Button onClick={()=>{setVisibleDelete(false)}} className="mr30 grayBorBut whiteBackBut" style={{width:"104px", height: '36px'}}>取消</Button>,
<Button className="redFontBut grayBorBut whiteBackBut" style={{width:"104px", height: '36px'}}>确认{type === '0' ? '删除' : type === '1' ? '公开' : '私有'}</Button>
<Button className="redFontBut grayBorBut whiteBackBut" style={{width:"104px", height: '36px'}} onClick={submitModal}>确认{type === '0' ? '删除' : type === '1' ? '公开' : type === '2' ? '私有' : '下架'}</Button>
]}
onCancel={()=>{setVisibleDelete(false)}}
>
<div className="font-16 titleTip mt20"><span className="circleRed font-18">!</span>您确定要{type === '0' ? '删除此Bot' : type === '1' ? `公开hhhBot` : `私有hhhBot`}</div>
<div className="deleteTip">{type === '0' ? '该操作无法撤销将会永久删除XXXXXBot' : type === '1' ? `公开后任何用户都可以安装此Bot` : `私有后此Bot将只能被Bot开发者账户安装`}</div>
<div className="font-16 titleTip mt20"><span className="circleRed font-18">!</span>您确定要{type === '0' ? '删除此Bot' : type === '1' ? `公开` : type === '2' ? '私有' : '下架'}{botDetail && botDetail.bot_name}</div>
<div className="deleteTip">{type === '0' ? `该操作无法撤销,将会永久删除${botDetail && botDetail.bot_name}` : type === '1' ? `公开后任何用户都可以安装此Bot` : type === '2' ? '私有后此Bot将只能被Bot开发者账户安装' : '下架后社区用户将无法在市场搜索到此Bot'}</div>
</Modal>
</div>
}

View File

@ -1,43 +1,76 @@
import React from "react";
import { Button, Form, Input } from "antd";
import { useState } from "react";
import React, { useEffect, useState } from "react";
import { Button, Form, Input, message } from "antd";
import MDEditor from '../../../../../../modules/tpm/challengesnew/tpm-md-editor';
import { Box } from "../../../../../Component/layout";
import miyao from '../../../../img/miyao.png';
import './index.scss';
import { useEffect } from "react";
// Bot
import { Link } from "react-router-dom";
import { getImageUrl } from 'educoder';
import { registerUpdateBot } from "../../../../../../softbot/api";
// import Avatar from './UpdateAvatarModal';
import UploadImage from '../../../../../../forge/Team/Component/UploadImage.jsx'
// Bot
function BasicInformation(props){
const {form} = props;
const {form, botDetail, match:{params:{id}}, setReload, current_user} = props;
const { getFieldDecorator, validateFields , setFieldsValue } = form;
const [ content , setContent ] = useState(undefined);
const [ avatarVisible , setAvatarVisible ] = useState(false);
const [ image , setImage ] = useState(undefined);
const [ imageFlag , setImageFlag ] = useState(false);
const [ imageId, setImageId] = useState(undefined);
useEffect(()=>{
console.log('111');
window.scrollTo(0, 0);
console.log('222');
},[])
function onCancelAvatar(){
setAvatarVisible(false);
}
function getImage(image){
setImageFlag(true);
setImage(image);
}
function getImageId(id){
setImageId(id);
}
function onContentChange(value){
setContent(value);
};
// bot
useEffect(()=>{
if(botDetail){
setContent(botDetail.bot_des);
setImage(botDetail.logo)
}
},[botDetail])
// Bot
function submit(e){
e.preventDefault();
validateFields((err, fieldsValue)=>{
if(err){
return;
}
console.log('fieldsValue', fieldsValue);
const params = {
...botDetail,
...fieldsValue,
bot_id: parseInt(id),
logo: imageId ? '/api/attachments/'+imageId : '/api/attachments/347240'
}
registerUpdateBot(params).then(res=>{
if(res && res.code === 200){
message.success("更改成功");
setReload(Math.random());
}
})
})
}
return <Box>
<div className="basicInformationBox">
{botDetail && <div className="basicInformationBox">
<p className="informationHead pb15 mb10">注册信息</p>
<div className="labelBox"><span className="label">Bot所有者</span>59897989liccha</div>
<div className="labelBox"><span className="label">Bot ID</span>4989895</div>
<div className="labelBox"><span className="label">客户端ID</span>xdeeqwerrqqrfrrrrrrr</div>
<div className="labelBox"><span className="label">主页URL</span>https://www.gitlink.org.cn/xiaoxiazi/organizes</div>
<div className="labelBox"><span className="label">Bot ID</span>{id}</div>
<div className="labelBox"><span className="label">客户端ID</span>{botDetail.client_id}</div>
<div className="labelBox"><span className="label">主页URL</span><Link to={`/softbot/${id}`} className="blueSpan">{window.location.origin + `/softbot/${id}`}</Link></div>
<div className="informationHead disFlex pb15 mt20 mb10">
客户端密钥
<Button className="themeCorBorBut">生成密钥</Button>
@ -56,14 +89,15 @@ function BasicInformation(props){
<p className="informationHead mt30 pb15">Bot信息</p>
<Form className="basicInformationForm mt10" onSubmit={submit}>
<Form.Item label="Bot名称" className="width80 botItem">
{getFieldDecorator("title",{
rules:[{required:true,message:"请输入Bot名称"}]
{getFieldDecorator("bot_name",{
rules:[{required:true,message:"请输入Bot名称"}],
initialValue: botDetail.bot_name
})(
<Input placeholder="请输入Bot名称" maxLength={200} className="height36"/>
<Input.TextArea placeholder="请输入Bot名称" maxLength={200} className="height36" autoSize={true}/>
)}
</Form.Item>
<Form.Item label="详细介绍" className="botItem introduce">
{getFieldDecorator("key",{
{getFieldDecorator("bot_des",{
rules:[]
})(
<MDEditor
@ -78,19 +112,29 @@ function BasicInformation(props){
)}
</Form.Item>
<Form.Item label="Webhook地址" className="width80 botItem">
{getFieldDecorator("title1",{
rules:[{required:true,message:"请输入Webhook地址"}]
{getFieldDecorator("webhook",{
rules:[{required:true,message:"请输入Webhook地址"}],
initialValue: botDetail.webhook
})(
<Input placeholder="请输入Webhook地址" maxLength={200} className="height36"/>
<Input.TextArea placeholder="请输入Webhook地址" maxLength={200} className="height36" autoSize={true}/>
)}
</Form.Item>
<Form.Item className="mt30"><Button style={{width:"129px", height: '36px'}} type="primary" htmlType="submit">保存修改</Button></Form.Item>
</Form>
</div>
</div>}
<div className="headPortraitBox">
<img src="" alt="" className="headPortrait"/>
<Button className="themeCorBorBut">修改头像</Button>
<UploadImage url={image && image.startsWith('/api/attachments/') ? getImageUrl(`/${image}`) : image} getImage={getImage} getImageId = {getImageId}/>
<Button className="themeCorBorBut ml5">修改头像</Button>
</div>
{/* {
avatarVisible &&
<Avatar
onCancel={onCancelAvatar}
avatarImg={getImageUrl(`/${current_user && current_user.image_url}`)}
id={current_user && current_user.user_id}
botDetail={botDetail}
/>
} */}
</Box>
}
export default Form.create()(BasicInformation);

View File

@ -11,6 +11,9 @@
.labelBox{
line-height: 40px;
}
.blueSpan{
color: $primary-color;
}
.label{
display: inline-block;
width: 76px;
@ -61,6 +64,17 @@
padding: 15px 0;
border-bottom: 1px dashed #e0e6f5;
}
.transferBotStatus{
background-color:rgba(70, 106, 255, 0.09);
border:1px solid $primary-color;
border-radius:4px;
color:rgba(0, 0, 0, 0.65);
display: flex;
align-items: center;
}
.icon-yuyue-lishi-shijian{
color: $primary-color;
}
}
.themeHeadModal{
.ant-modal-header{
@ -83,6 +97,7 @@
.ant-modal-body{
background-image:linear-gradient(42.46deg,#ffffff 0%,#ffffff 48.54%,#ebf0ff 100%);
}
.makeOverErrorTip{color:#f60011;}
}
.putawayBox{
width: 100%;

View File

@ -1,16 +1,17 @@
import React from "react";
import { Button, Checkbox, Form, Input, Select } from "antd";
import { Button, Checkbox, Form, Input, message, Select } from "antd";
import { useState } from "react";
import '../../new/index.scss';
import './index.scss';
import { registerUpdateBot } from "../../../../../../softbot/api";
const {Option} = Select;
// Bot
function Jurisdiction(props){
const {form} = props;
const { getFieldDecorator, validateFields , setFieldsValue } = form;
const resource = [{value: '0', name: '无权限'}, {value: '1', name: '只读'}, {value: '2', name: '读写'}];
const [ codeSelectValue , setCodeSelectValue ] = useState(resource[0].value);
const [ prSelectValue , setPrSelectValue ] = useState(resource[0].value);
const {form, botDetail, setReload, match:{params:{id}}} = props;
const {getFieldDecorator, validateFields , setFieldsValue } = form;
const resource = [{value: 2, name: '无权限'}, {value: 0, name: '只读'}, {value: 1, name: '读写'}];
const [codeSelectValue , setCodeSelectValue ] = useState(botDetail && botDetail.limit_and_events.juris_diction_code);
const [prSelectValue , setPrSelectValue ] = useState(botDetail && botDetail.limit_and_events.juris_diction_pr);
function codeControl(e){
setCodeSelectValue(e);
@ -29,48 +30,65 @@ function Jurisdiction(props){
if(err){
return;
}
console.log('fieldsValue', fieldsValue);
const {juris_diction_code, juris_diction_pr, event_code, event_pr} = fieldsValue;
const params = {
...botDetail,
bot_id: parseInt(id),
limit_and_events: {
event_code: event_code ? event_code.toString() : "",
event_pr: event_pr ? event_pr.toString() : "",
juris_diction_code,
juris_diction_pr
},
}
registerUpdateBot(params).then(res=>{
if(res && res.code === 200){
message.success("更改成功");
setReload(Math.random());
}
})
})
}
return <Form className="createExploitForm jurisdictionBox" onSubmit={submit}>
{botDetail && <div>
<div className="resourceTitle font-16 pb15 mb10">仓库访问权限</div>
<Form.Item label="代码库权限" className="resourceBox botItem dashedBorder">
<div className="color-99">代码库git推送分支的创建与删除</div>
{getFieldDecorator("resource1",{initialValue: resource[0].value, getValueFromEvent: codeControl})(
<Select>
{resource.map(item=>{return <Option value={item.value} key={item.value}>{item.name}</Option>})}
</Select>
)}
</Form.Item>
<div className="dashedBor"></div>
<Form.Item label="合并请求(PR)权限" className="resourceBox botItem">
<div className="color-99">合并请求的打开关闭编辑分配</div>
{getFieldDecorator("resource2",{initialValue: resource[0].value, getValueFromEvent: prControl})(
<Select>
{resource.map(item=>{return <Option value={item.value} key={item.value}>{item.name}</Option>})}
</Select>
)}
</Form.Item>
{(codeSelectValue !== resource[0].value || prSelectValue !== resource[0].value) && <div className="resourceTitle font-16 pb15 mb10">订阅事件</div>}
{codeSelectValue !== resource[0].value && <Form.Item label="代码库事件" className="botItem width50 checkBox three dashedBorder">
{getFieldDecorator("title2")(
<Checkbox.Group>
<Checkbox value={0}>推送<br/><span className="color-99">git推送到存储库</span></Checkbox>
<Checkbox value={1}>创建<br/><span className="color-99">创建分支或标签</span></Checkbox>
<Checkbox value={2}>删除<br/><span className="color-99">删除分支或标签</span></Checkbox>
</Checkbox.Group>
)}
</Form.Item>}
{(codeSelectValue !== resource[0].value && prSelectValue !== resource[0].value) && <div className="dashedBor"></div>}
{prSelectValue !== resource[0].value && <Form.Item label="合并请求事件" className="botItem width50 checkBox">
{getFieldDecorator("title5")(
<Checkbox.Group>
<Checkbox value={0}>合并请求<br/><span className="color-99">合并请求被打开被关闭被重新打开或被编辑</span></Checkbox>
<Checkbox value={1}>合并请求分配<br/><span className="color-99">合并请求被分配或取消分配</span></Checkbox>
</Checkbox.Group>
)}
</Form.Item>}
<Form.Item className="mt30"><Button style={{width:"129px", height: '36px'}} type="primary" htmlType="submit">保存修改</Button></Form.Item>
<Form.Item label="代码库权限" className="resourceBox botItem dashedBorder">
<div className="color-99">代码库git推送分支的创建与删除</div>
{getFieldDecorator("juris_diction_code",{initialValue: botDetail.limit_and_events.juris_diction_code, getValueFromEvent: codeControl})(
<Select>
{resource.map(item=>{return <Option value={item.value} key={item.value}>{item.name}</Option>})}
</Select>
)}
</Form.Item>
<div className="dashedBor"></div>
<Form.Item label="合并请求(PR)权限" className="resourceBox botItem">
<div className="color-99">合并请求的打开关闭编辑分配</div>
{getFieldDecorator("juris_diction_pr",{initialValue: botDetail.limit_and_events.juris_diction_pr, getValueFromEvent: prControl})(
<Select>
{resource.map(item=>{return <Option value={item.value} key={item.value}>{item.name}</Option>})}
</Select>
)}
</Form.Item>
{(codeSelectValue !== resource[0].value || prSelectValue !== resource[0].value) && <div className="resourceTitle font-16 pb15 mb10">订阅事件</div>}
{codeSelectValue !== resource[0].value && <Form.Item label="代码库事件" className="botItem width50 checkBox three dashedBorder">
{getFieldDecorator("event_code", {initialValue: botDetail.limit_and_events.event_code})(
<Checkbox.Group>
<Checkbox value={0}>推送<br/><span className="color-99">git推送到存储库</span></Checkbox>
<Checkbox value={1}>创建<br/><span className="color-99">创建分支或标签</span></Checkbox>
<Checkbox value={2}>删除<br/><span className="color-99">删除分支或标签</span></Checkbox>
</Checkbox.Group>
)}
</Form.Item>}
{(codeSelectValue !== resource[0].value && prSelectValue !== resource[0].value) && <div className="dashedBor"></div>}
{prSelectValue !== resource[0].value && <Form.Item label="合并请求事件" className="botItem width50 checkBox">
{getFieldDecorator("event_pr", {initialValue: botDetail.limit_and_events.event_pr})(
<Checkbox.Group>
<Checkbox value={3}>合并请求<br/><span className="color-99">合并请求被打开被关闭被重新打开或被编辑</span></Checkbox>
<Checkbox value={4}>合并请求分配<br/><span className="color-99">合并请求被分配或取消分配</span></Checkbox>
</Checkbox.Group>
)}
</Form.Item>}
<Form.Item className="mt30"><Button style={{width:"129px", height: '36px'}} type="primary" htmlType="submit">保存修改</Button></Form.Item></div>}
</Form>
}
export default Form.create()(Jurisdiction);

View File

@ -1,16 +1,62 @@
import React, {forwardRef, useState} from "react";
import { Button, Checkbox, Form, Input, Select } from "antd";
import React, {forwardRef, useState, useEffect} from "react";
import { Button, Checkbox, Form, Input, message, Select } from "antd";
import { Link } from "react-router-dom";
import './index.scss';
import MdEditor from "../../../../../../modules/tpm/challengesnew/tpm-md-editor";
import { marketBot, getAllBotCategory, getMarketBotById, updateMarketBot } from "../../../../../../softbot/api";
import moment from "moment";
const {Option} = Select;
function Putaway(props){
const {form} = props;
const {form, current_user, match:{params:{id}}, botDetail, location:{pathname}} = props;
const { getFieldDecorator, validateFields , setFieldsValue } = form;
const resource = [{value: '0', name: '项目管理'}, {value: '1', name: '代码管理'}, {value: '2', name: '测试部署'}, {value: '3', name: '其他'}];
const [ resource, setResource] = useState([]);
const [ resourceFirst, setResourceFirst] = useState([]);
const [ resourceSecond, setResourceSecond] = useState([]);
const [ content , setContent ] = useState(undefined);
const [ disabled , setDisabled ] = useState(undefined);
const [ detail, setDetail] = useState(undefined);
const [ isEdit, setIsEdit] = useState(undefined);
useEffect(()=>{
//
getAllBotCategory().then(res=>{
if(res && res.code === 200){
setResource(res.data.category_list);
setResourceFirst(res.data.category_list);
setResourceSecond(res.data.category_list);
}
})
if(pathname && pathname.endsWith("/putaway/edit")){
setIsEdit(true);
setDisabled(true);
getMarketBotById({bot_id: id}).then(res=>{
if(res && res.code === 200){
setDetail({
...res.data
});
setContent(res.data.market_intro);
}
})
}else{
setIsEdit(false);
if(botDetail){
const {bot_des, bot_name, webhook} = botDetail;
setDetail({
bot_id: id,
category: "",
first_func: undefined,
logo: "",
market_desc: undefined,
market_name: bot_name,
market_time: undefined,
second_func: undefined,
webhook: webhook
})
setContent(bot_des);
}
}
}, [pathname, botDetail])
//
function onChange(e){
@ -28,48 +74,94 @@ function Putaway(props){
if(err){
return;
}
const {logo} = botDetail;
if(isEdit){
// bot
updateMarketBot({
...fieldsValue,
category: "",
is_receive_ag1: 1,
is_receive_ag2: 0,
logo: logo,
market_time: "",
user_id: current_user && current_user.user_id,
bot_id: parseInt(id),
}).then(res=>{
if(res && res.code === 200){
message.success("修改成功");
}else{
message.error(res.data);
}
})
}else{
// bot
marketBot({
...fieldsValue,
user_id: current_user && current_user.user_id,
bot_id: parseInt(id),
category: "",
is_receive_ag1: disabled ? 1 : 0,
is_receive_ag2: 0,
logo: logo,
market_time: moment().format(),
}).then(res=>{
if(res && res.code === -1){
message.error(res.data);
}else{
message.success("成功上架市场");
props.history.push('/settings/dispositionBot');
}
})
}
})
}
return <div className="putawayBox">
<div className="putaHead pb10 font-18 mb5">
<a href="#" className="font-16">高级选项&gt;</a><b>上架Bot市场</b>
</div>
<Form className="putawayForm" onSubmit={submit}>
{detail && <Form className="putawayForm" onSubmit={submit}>
<Form.Item label="上架Bot市场名称" className="width50 oneItem">
{getFieldDecorator("a",{
rules:[{required:true,message:"请输入上架Bot市场名称"}]
{getFieldDecorator("market_name",{
rules:[{required:true,message:"请输入上架Bot市场名称"}],
initialValue: detail.market_name
})(
<Input placeholder="请输入上架Bot市场名称" maxLength={200} className="height36"/>
<Input.TextArea placeholder="请输入上架Bot市场名称" maxLength={200} className="height36" autoSize={true}/>
)}
</Form.Item>
<Form.Item label="简要介绍" className="oneItem">
{getFieldDecorator("b",{
rules:[{required:true,message:"请输入简要介绍"}]
{getFieldDecorator("market_desc",{
rules:[{required:true,message:"请输入简要介绍"}],
initialValue: detail.market_desc
})(
<Input.TextArea placeholder="请输入简要介绍的内容" maxLength={50} className="height36"/>
<Input.TextArea placeholder="请输入简要介绍的内容" maxLength={200} className="height36" autoSize={true}/>
)}
</Form.Item>
<div className="selectBox">
<Form.Item label="主要功能" className="selectOne oneItem">
{getFieldDecorator("c",{
rules:[{required:true,message:"请选择主要功能"}]
{getFieldDecorator("first_func",{
rules:[{required:true,message:"请选择主要功能"}],
initialValue: detail.first_func
})(
<Select placeholder="请选择">
{resource.map(item=>{return <Option value={item.value} key={item.value}>{item.name}</Option>})}
<Select placeholder="请选择" onChange={(value)=>{setResourceSecond(resource.filter(item => item !== value))}}>
{resourceFirst.map(item=>{return <Option value={item} key={item}>{item}</Option>})}
</Select>
)}
</Form.Item>
<Form.Item label="次要功能" className="selectOne oneItem">
{getFieldDecorator("d")(
<Select placeholder="请选择">
{resource.map(item=>{return <Option value={item.value} key={item.value}>{item.name}</Option>})}
{getFieldDecorator("second_func",{
initialValue: detail.second_func
})(
<Select placeholder="请选择" onChange={(value)=>{setResourceFirst(resource.filter(item => item !== value))}}>
{resourceSecond.map(item=>{return <Option value={item} key={item}>{item}</Option>})}
</Select>
)}
</Form.Item>
</div>
<Form.Item label="详细介绍" className="oneItem introduce">
{getFieldDecorator("e",{
rules:[{required:true,message:"请输入详细介绍"}]
{getFieldDecorator("market_intro",{
rules:[{required:true,message:"请输入详细介绍"}],
initialValue: content
})(
<MdEditor
placeholder={"请输入详细介绍"}
@ -82,17 +174,18 @@ function Putaway(props){
)}
</Form.Item>
<Form.Item label="订阅接收Webhook地址" className="width50 oneItem">
{getFieldDecorator("f",{
rules:[{required:true,message:"请输入Webhook地址"}]
{getFieldDecorator("webhook",{
rules:[{required:true,message:"请输入Webhook地址"}],
initialValue: detail.webhook
})(
<Input placeholder="请输入Webhook地址" maxLength={200} className="height36"/>
<Input.TextArea placeholder="请输入Webhook地址" maxLength={200} className="height36" autoSize={true}/>
)}
</Form.Item>
<Form.Item>
{!isEdit && <Form.Item>
<Checkbox onChange={onChange}>我接受GitLink Bot市场开发者协议</Checkbox>
</Form.Item>
<Form.Item><Button style={{width:"129px", height: '36px'}} type="primary" htmlType="submit" disabled={!disabled} className="putawayBut">申请上架</Button></Form.Item>
</Form>
</Form.Item>}
<Form.Item><Button style={{width:"129px", height: '36px'}} type="primary" htmlType="submit" disabled={!disabled} className="putawayBut mt20">{isEdit ? '保存修改' : '申请上架'}</Button></Form.Item>
</Form>}
</div>
}
export default Form.create()(forwardRef(Putaway));

View File

@ -1,4 +1,4 @@
import React, {useEffect} from "react";
import React, {useEffect, useState} from "react";
import { Route, Switch } from "react-router-dom";
import Loadable from "react-loadable";
import Loading from "../../../../../Loading";
@ -7,6 +7,7 @@ import { TPMIndexHOC } from "../../../../../modules/tpm/TPMIndexHOC";
import { Box } from "../../../../Component/layout";
import './index.scss';
import { Button } from "antd";
import { getRegisterBot } from "../../../../../softbot/api";
const BasicInformation = Loadable({
loader: () => import("./compenent/basicInformation"),
@ -27,10 +28,21 @@ const Putaway = Loadable({
// bot
function ConfigurateBot(props){
const {match} = props;
const { pathname } = props.location;
const {params:{id}} = match;
console.log('444', id, props);
const {match:{params:{id}}, current_user, location:{pathname}} = props;
const [reload, setReload] = useState(undefined);
const [botDetail, setBotDetail] = useState(undefined);
useEffect(()=>{
getRegisterBot({
user_id: current_user && current_user.user_id,
bot_id: id
}).then(res=>{
if(res && res.code === 200){
setBotDetail(res.data.bot_output_vo);
}
})
}, [reload])
return <div className="configurateBotBox">
<div className="configurateBotHead mb30">
<span className="font-18 configurateBotTitle">Bot配置</span>
@ -47,24 +59,30 @@ function ConfigurateBot(props){
<Route
path="/settings/exploitBot/configuration/:id/advanced/putaway"
render={(p) => (
<Putaway {...props} {...p}/>
<Putaway {...props} {...p} botDetail={botDetail} setReload={setReload}/>
)}
></Route>
<Route
path="/settings/exploitBot/configuration/:id/advanced/putaway/edit"
render={(p) => (
<Putaway {...props} {...p} botDetail={botDetail} setReload={setReload}/>
)}
></Route>
<Route
path="/settings/exploitBot/configuration/:id/basic"
render={(p)=>(<BasicInformation {...props} {...p}/>)}
render={(p)=>(<BasicInformation {...props} {...p} botDetail={botDetail} setReload={setReload}/>)}
></Route>
<Route
path="/settings/exploitBot/configuration/:id/jurisdiction"
render={(p)=>(<Jurisdiction {...props} {...p}/>)}
render={(p)=>(<Jurisdiction {...props} {...p} botDetail={botDetail} setReload={setReload}/>)}
></Route>
<Route
path="/settings/exploitBot/configuration/:id/advanced"
render={(p)=>(<AdvancedInformation {...props} {...p}/>)}
render={(p)=>(<AdvancedInformation {...props} {...p} botDetail={botDetail} setReload={setReload}/>)}
></Route>
<Route
path="/settings/exploitBot/configuration/:id"
render={(p)=>(<BasicInformation {...props} {...p}/>)}
render={(p)=>(<BasicInformation {...props} {...p} botDetail={botDetail} setReload={setReload}/>)}
></Route>
</Switch>
</Box>

View File

@ -1,12 +1,70 @@
import React from "react";
import { Button, Icon } from "antd";
import React, { useState, useEffect } from "react";
import { Button, Icon, message, Modal } from "antd";
import './index.scss';
import { Link } from "react-router-dom";
import { useState } from "react";
import { getImageUrl } from 'educoder';
import { getMyBot, getTransferToBot, receiveTransferBot, refuseTransferBot } from "../../../../softbot/api";
import nullBot from '../../../../softbot/image/notBot.png';
import moment from "moment";
function ExploitBot(props){
const [makeOverList, setMakeOverList] = useState([{botName: 'botName', userName: 'userName', time: 'time'}, {botName: 'botName', userName: 'userName', time: 'time'}]);
const [botList, setBotList] = useState([{botName: '此处为名称标题内容', userName: 'userName', id: '0'}, {botName: '此处为名称标题内容', userName: 'userName', id: '1'}]);
const {current_user} = props;
const [makeOverList, setMakeOverList] = useState([]);
const [botList, setBotList] = useState(undefined);
const [visible, setVisible] = useState(false);
const [refuseBotDetail, setRefuseBotDetail] = useState(undefined);
const [reload, setReload] = useState(undefined);
useEffect(()=>{
getMyBot({
user_id: current_user && current_user.user_id,
page_no: 1,
page_size: 1000
}).then(res=>{
if(res && res.code === 200){
setBotList(res.data.list);
}
})
getTransferToBot({
user_id: current_user && current_user.user_id,
state: "2"
}).then(res=>{
if(res && res.code === 200){
setMakeOverList(res.data.bot_list);
}
})
}, [reload])
// bot
function receiveBot(info){
receiveTransferBot({
bot_id: info.bot_id,
transfer_from_id: info.transfer_id,
transfer_to_id: current_user && current_user.user_id
}).then(res=>{
if(res && res.code === 200){
message.success('操作成功');
setReload(Math.random());
}
})
}
// bot
function refuseBot(){
refuseTransferBot({
bot_id: refuseBotDetail.bot_id,
transfer_from_bot: refuseBotDetail.transfer_id,
transfer_to_bot: current_user && current_user.user_id
}).then(res=>{
if(res && res.code === 200){
setVisible(false);
setRefuseBotDetail(undefined);
message.success('操作成功');
setReload(Math.random());
}
})
}
return <div>
<div className="exploitHead font-18">
<span>Bot开发者配置</span>
@ -14,29 +72,49 @@ function ExploitBot(props){
</div>
{/* bot转让接收按钮显示区域 */}
<div className="makeOverBox">
{makeOverList.length > 0 && <div className="makeOverBox">
{makeOverList.map((item, index)=>{return <div className="makeOverItem" key={index}>
<div>
<p className="botName font-15">{item.botName}</p>
<p className="userName">{item.userName}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{item.time}</p>
<p className="botName font-15">{item.bot_name}</p>
<p className="userName">{item.userName || '转让者姓名'}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{moment(item.transfer_date).format('YYYY-MM-DD HH:mm')}</p>
</div>
<div>
<Button className="themeCorBorBut" style={{width: '68px', height: '36px'}}>接收</Button>
<Button className="dangerBorBut ml20" style={{width: '68px', height: '36px'}}>拒绝</Button>
<Button className="themeCorBorBut" style={{width: '68px', height: '36px'}} onClick={()=>{receiveBot(item)}}>接收</Button>
<Button className="dangerBorBut ml20" style={{width: '68px', height: '36px'}} onClick={()=>{setRefuseBotDetail(item); setVisible(true)}}>拒绝</Button>
</div>
</div>})}
</div>
</div>}
{/* bot列表显示区域 */}
{botList.length > 0 ? <div className="softBotListBox">
{botList && (botList.length > 0 ? <div className="softBotListBox">
{botList.map((item, index)=>{return <div className="softBotItem" key={index}>
<div>
<img src="" alt="" className="imgBox mr10"/>
<span className="font-15">{item.botName}</span>
<div className="botOneLine">
<img src={getImageUrl(item.logo)} alt="" className="imgBox mr10"/>
<span className="font-15">{item.bot_name}</span>
</div>
<Button className="themeCorBorBut" style={{width: '68px', height: '36px'}}><Link to={`/settings/exploitBot/configuration/${item.id}`}>编辑</Link></Button>
<Button className="themeCorBorBut ml30" style={{width: '68px', height: '36px'}}><Link to={`/settings/exploitBot/configuration/${item.bot_id}`}>编辑</Link></Button>
</div>})}
</div> : <div className="font-16 softBotListBox">欢迎使用Bot! Bot可以帮助项目贡献者处理繁杂的项目任务比如关闭疑修合并请求在使用之前请先注册一个Bot</div>}
</div> : <div className="nullBotsBox mt100">
<img src={nullBot} alt="" width={62}/>
<p className="font-18 showBigTip">您当前暂未注册任何Bot</p>
<div className="showTip font-14">欢迎使用Bot! Bot可以帮助项目贡献者处理繁杂的项目任务比如关闭疑修合并请求在使用之前请先注册一个Bot!</div>
</div>)}
<Modal
className="f8HeadModal"
width="550px"
title={`拒绝${refuseBotDetail && refuseBotDetail.bot_name}Bot`}
visible={visible}
maskClosable={false}
footer={[
<Button onClick={()=>{setVisible(false)}} className="mr30 grayBorBut whiteBackBut" style={{width:"104px", height: '36px'}}>取消</Button>,
<Button className="redFontBut grayBorBut whiteBackBut" style={{width:"104px", height: '36px'}} onClick={refuseBot}>确认</Button>
]}
onCancel={()=>{setVisible(false)}}
>
<div className="font-16 titleTip mt20"><span className="circleRed font-18">!</span>您确定要拒绝此Bot吗</div>
<div className="deleteTip">拒绝后开发Bot权限将返回至转让人</div>
</Modal>
</div>
}
export default ExploitBot;

View File

@ -60,7 +60,22 @@
.imgBox{
width: 44px;
height: 44px;
background-color: yellow;
border-radius: 50%;
}
}
.nullBotsBox{
border-radius: 4px 4px 0px 0px;
text-align: center;
padding: 25px 158px 65px;
.showBigTip{
color:#333333;
margin-top: 16px;
margin-bottom: 22px !important;
}
.showTip{color: #666;}
}
.botOneLine{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

View File

@ -1,14 +1,15 @@
import React, { forwardRef, useState } from "react";
import { Button, Checkbox, Form, Input, Select } from "antd";
import { Button, Checkbox, Form, Input, message, Radio, Select } from "antd";
import { Link } from "react-router-dom";
import MDEditor from '../../../../../modules/tpm/challengesnew/tpm-md-editor';
import './index.scss';
import { registerBot } from "../../../../../softbot/api";
const {Option} = Select;
function Disposition(props){
const {form} = props;
const {form, current_user} = props;
const { getFieldDecorator, validateFields , setFieldsValue } = form;
const resource = [{value: '0', name: '无权限'}, {value: '1', name: '只读'}, {value: '2', name: '读写'}];
const resource = [{value: 2, name: '无权限'}, {value: 0, name: '只读'}, {value: 1, name: '读写'}];
const [ content , setContent ] = useState(undefined);
const [ codeSelectValue , setCodeSelectValue ] = useState(resource[0].value);
@ -35,7 +36,26 @@ function Disposition(props){
if(err){
return;
}
console.log('fieldsValue', fieldsValue);
const {bot_name, bot_des, webhook, is_public, juris_diction_code, juris_diction_pr, event_code, event_pr} = fieldsValue;
const param = {
bot_name, bot_des, webhook, is_public,
user_id: current_user && current_user.user_id,
logo: '/api/attachments/347240',
limit_and_events: {
event_code: event_code ? event_code.toString() : "",
event_pr: event_pr ? event_pr.toString() : "",
juris_diction_code,
juris_diction_pr
},
}
registerBot(param).then(res=>{
if(res && res.code === 200){
message.success('注册成功');
props.history.push('/settings/exploitBot/configuration/'+res.data.bot_id);
}else{
message.success('注册失败: '+res.data);
}
})
})
}
@ -45,14 +65,14 @@ function Disposition(props){
</div>
<Form className="createExploitForm" onSubmit={submit}>
<Form.Item label="Bot名称" className="width50 botItem">
{getFieldDecorator("title",{
{getFieldDecorator("bot_name",{
rules:[{required:true,message:"请输入Bot名称"}]
})(
<Input placeholder="请输入Bot名称" maxLength={200} className="height36"/>
<Input.TextArea placeholder="请输入Bot名称" maxLength={200} className="height36" autoSize={true}/>
)}
</Form.Item>
<Form.Item label="详细介绍" className="botItem introduce">
{getFieldDecorator("key",{
{getFieldDecorator("bot_des",{
rules:[]
})(
<MDEditor
@ -66,16 +86,16 @@ function Disposition(props){
)}
</Form.Item>
<Form.Item label="Webhook地址" className="width50 botItem">
{getFieldDecorator("title1",{
{getFieldDecorator("webhook",{
rules:[{required:true,message:"请输入Webhook地址"}]
})(
<Input placeholder="请输入Webhook地址" maxLength={200} className="height36"/>
<Input.TextArea placeholder="请输入Webhook地址" maxLength={200} className="height36" autoSize={true}/>
)}
</Form.Item>
<div className="resourceTitle font-16 pb15 mb10">仓库访问权限</div>
<Form.Item label="代码库权限" className="resourceBox botItem dashedBorder">
<div className="color-99">代码库git推送分支的创建与删除</div>
{getFieldDecorator("resource1",{initialValue: resource[0].value, getValueFromEvent: codeControl})(
{getFieldDecorator("juris_diction_code",{initialValue: resource[0].value, getValueFromEvent: codeControl})(
<Select>
{resource.map(item=>{return <Option value={item.value} key={item.value}>{item.name}</Option>})}
</Select>
@ -84,7 +104,7 @@ function Disposition(props){
<div className="dashedBor"></div>
<Form.Item label="合并请求(PR)权限" className="resourceBox botItem">
<div className="color-99">合并请求的打开关闭编辑分配</div>
{getFieldDecorator("resource2",{initialValue: resource[0].value, getValueFromEvent: prControl})(
{getFieldDecorator("juris_diction_pr",{initialValue: resource[0].value, getValueFromEvent: prControl})(
<Select>
{resource.map(item=>{return <Option value={item.value} key={item.value}>{item.name}</Option>})}
</Select>
@ -92,7 +112,7 @@ function Disposition(props){
</Form.Item>
{(codeSelectValue !== resource[0].value || prSelectValue !== resource[0].value) && <div className="resourceTitle font-16 pb15 mb10">订阅事件</div>}
{codeSelectValue !== resource[0].value && <Form.Item label="代码库事件" className="botItem width50 checkBox three dashedBorder">
{getFieldDecorator("title2")(
{getFieldDecorator("event_code")(
<Checkbox.Group>
<Checkbox value={0}>推送<br/><span className="color-99">git推送到存储库</span></Checkbox>
<Checkbox value={1}>创建<br/><span className="color-99">创建分支或标签</span></Checkbox>
@ -102,19 +122,19 @@ function Disposition(props){
</Form.Item>}
{(codeSelectValue !== resource[0].value && prSelectValue !== resource[0].value) && <div className="dashedBor"></div>}
{prSelectValue !== resource[0].value && <Form.Item label="合并请求事件" className="botItem width50 checkBox">
{getFieldDecorator("title5")(
{getFieldDecorator("event_pr")(
<Checkbox.Group>
<Checkbox value={0}>合并请求<br/><span className="color-99">合并请求被打开被关闭被重新打开或被编辑</span></Checkbox>
<Checkbox value={1}>合并请求分配<br/><span className="color-99">合并请求被分配或取消分配</span></Checkbox>
<Checkbox value={3}>合并请求<br/><span className="color-99">合并请求被打开被关闭被重新打开或被编辑</span></Checkbox>
<Checkbox value={4}>合并请求分配<br/><span className="color-99">合并请求被分配或取消分配</span></Checkbox>
</Checkbox.Group>
)}
</Form.Item>}
<Form.Item label="公/私有设置" className="botItem resourceTitleItem">
{getFieldDecorator("title3")(
<Checkbox.Group>
<Checkbox value={0}>公开</Checkbox>
<Checkbox value={1}>私有</Checkbox>
</Checkbox.Group>
{getFieldDecorator("is_public")(
<Radio.Group>
<Radio value={1}>公开</Radio>
<Radio value={0}>私有</Radio>
</Radio.Group>
)}
</Form.Item>
<Form.Item><Button style={{width:"129px", height: '36px'}} type="primary" htmlType="submit">注册Bot</Button></Form.Item>

View File

@ -15,6 +15,9 @@
justify-content: space-between;
position: relative;
}
.resourceBox .ant-select{
width: auto;
}
.width50{
width: 60%;
&.checkBox{

View File

@ -315,7 +315,6 @@
.imgBox{
width: 44px;
height: 44px;
background-color: yellow;
border-radius: 50%;
}
}

View File

@ -3,21 +3,36 @@ import { Link } from "react-router-dom";
import { Button } from "antd";
import nullBot from '../../softbot/image/notBot.png';
import './setting.scss';
import { useEffect } from "react";
import { getStoreAllInstallBots } from "../../softbot/api";
import { getImageUrl } from 'educoder';
function SoftBot(props){
const {projectDetail} = props;
const [botList, setBotList] = useState(undefined);
useEffect(()=>{
// bot
projectDetail && getStoreAllInstallBots({
store_id: projectDetail.project_id
}).then(res=>{
if(res && res.code === 200){
setBotList(res.data.install_bot_infos);
}
})
}, [projectDetail])
function SoftBot(){
// {botName: '', status: '0', id: '0'}, {botName: '', status: '1', id: '1'}
const [botList, setBotList] = useState([]);
return <div className="softBotClass">
<div className="softBoxHeadTitle font-18">Bot安装</div>
{/* bot列表显示区域 */}
{botList.length > 0 ? <div className="botListBox">
{botList && (botList.length > 0 ? <div className="botListBox">
{botList.map((item, index)=>{return <div className="disBotItem" key={index}>
<div>
<img src="" alt="" className="imgBox mr20"/>
<span className="font-15">{item.botName}</span>
<span className={`statusBox font-12 ml10 ${item.status === '0' ? 'active' : ''}`}>{item.status === '0' ? '启用' : '挂起'}</span>
<img src={getImageUrl(item.logo)} alt="" className="imgBox mr20"/>
<span className="font-15">{item.bot_name}</span>
<span className={`statusBox font-12 ml10 ${item.state === 0 ? '' : 'active'}`}>{item.state === 0 ? '挂起' : '启用'}</span>
</div>
<Button className="themeCorBorBut" style={{width: '68px', height: '36px'}}><Link to={`/settings/dispositionBot/${item.id}`}>配置</Link></Button>
<Button className="themeCorBorBut" style={{width: '68px', height: '36px'}}><Link to={`/settings/dispositionBot/${item.bot_id}`}>配置</Link></Button>
</div>})}
</div> : <div className="nullBotBox mt20">
<img src={nullBot} alt="" width={62}/>
@ -25,7 +40,7 @@ function SoftBot(){
<div className="showTip font-14">Bot可以帮助项目贡献者处理繁杂的项目任务比如关闭疑修合并请求等以节约时间精力提升开发效率快去市场中挑选一个适合您项目的Bot吧!</div>
<div className="borTip"></div>
<Button type="primary" style={{width: '112px', height: '36px', padding: 0}}><Link to={'/softbot'}>去Bot市场逛逛</Link></Button>
</div>}
</div>)}
</div>
}
export default SoftBot

View File

@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { Upload , Icon , message } from "antd";
import { getUploadActionUrl } from 'educoder';
function UploadImage({ getImage , url }){
function UploadImage({ getImage , url, getImageId }){
const [ imageUrl , setImageUrl ] = useState(undefined);
useEffect(()=>{
if(url){
@ -33,6 +33,8 @@ function UploadImage({ getImage , url }){
//
function handleChange(info){
if(info && info.file && info.file.status === "done"){
console.log('info', info);
getImageId && getImageId(info.file.response.id);
getBase64(info.file.originFileObj, imageUrl =>
setImageUrl(imageUrl)
);

View File

@ -68,7 +68,6 @@ export default function javaFetch(actionUrl){
}
},
error => {
console.log(error);
let res = error.response||{};
if (res.status === 400) {
message.error(res.data.message || '操作失败');

View File

@ -6,6 +6,7 @@ import 'cropperjs/dist/cropper.css';
import axios from 'axios';
function Index({onCancel,avatarImg,login}){
console.log('avatarImg,login', avatarImg,login);
const [ avatarPhoto , setAvatarPhoto ] = useState(avatarImg);

View File

@ -74,8 +74,8 @@ function md_elocalStorage(editor, mdu, id) {
return tid
}
export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, className = '', noStorage = false, imageExpand = true, placeholder = '', width = '100%', height = 400, initValue = '', emoji, watch, showNullButton = false, showResizeBar = false, startInit = true , forMember = true , isCanAtme = false , changeAtWhoLoginList, owner, projectsId }) => {
// isFocus是否聚焦到md编译器
export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, className = '', noStorage = false, imageExpand = true, placeholder = '', width = '100%', height = 400, initValue = '', emoji, watch, showNullButton = false, showResizeBar = false, startInit = true , forMember = true , isCanAtme = false , changeAtWhoLoginList, owner, projectsId, isFocus = true }) => {
const editorEl = useRef();
const resizeBarEl = useRef();
const [editorInstance, setEditorInstance] = useState();
@ -114,7 +114,7 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
if (entry.target.offsetHeight > 0 || entry.target.offsetWidth > 0) {
editorInstance.resize();
editorInstance.cm.refresh();
editorInstance.cm.focus();
isFocus && editorInstance.cm.focus();
}
}
})

View File

@ -1,19 +1,217 @@
import fetch from './fetch';
// 获取当前用户项目报名信息
// export function getAllBotCategory(params) {
// return fetch({
// url: `/getAllBotCategory`,
// method: 'get',
// params
// });
// }
//报名夏令营
export function getAllBotCategory(data) {
// 获取个人注册Bot
export function getMyBot(params) {
return fetch({
url: '/getAllBotCategory',
method: 'post',
// data: data
url: `/getMyBot`,
method: 'get',
params
});
}
// 查看被转让的bot列表
export function getTransferToBot(params) {
return fetch({
url: '/getTransferToBot',
method: 'get',
params
});
}
// 用户注册bot
export function registerBot(data) {
return fetch({
url: '/registerBot',
method: 'post',
data: data
});
}
// 获取bot市场 分类列表
export function getAllBotCategory(params) {
return fetch({
url: `/getAllBotCategory`,
method: 'get',
params
});
}
// 获取bot市场 softbot列表
export function getContentsLikeNameAndFunc(params) {
return fetch({
url: `/getContentsLikeNameAndFunc`,
method: 'get',
params
});
}
// 获取bot详情
export function getBotDetail(params) {
return fetch({
url: `/getBotDetail`,
method: 'get',
params
});
}
// 用户安装bot
export function installMarketBot(data) {
return fetch({
url: '/installMarketBot',
method: 'post',
data: data
});
}
// 接受转让的bot
export function receiveTransferBot(data) {
return fetch({
url: '/receiveTransferBot',
method: 'post',
data: data
});
}
// 拒绝转让的bot
export function refuseTransferBot(data) {
return fetch({
url: '/refuseTransferBot',
method: 'post',
data: data
});
}
// 获取已经安装的Bot详情信息
export function getInstallBot(params) {
return fetch({
url: `/getInstallBot`,
method: 'get',
params
});
}
// 个人删除Bot
export function deleteBot(data) {
return fetch({
url: '/deleteBot',
method: 'post',
data: data
});
}
// 上架bot
export function marketBot(data) {
return fetch({
url: '/marketBot',
method: 'post',
data: data
});
}
// 转让bot
export function transferBot(data) {
return fetch({
url: '/transferBot',
method: 'post',
data: data
});
}
// 通过BotId查询MarketBot
export function getMarketBotById(params) {
return fetch({
url: `/getMarketBotById`,
method: 'get',
params
});
}
// 配置安装的Bot
export function updateInstallBot(data) {
return fetch({
url: '/updateInstallBot',
method: 'post',
data: data
});
}
// 仓库安装的所有bot
export function getStoreAllInstallBots(params) {
return fetch({
url: `/getStoreAllInstallBots`,
method: 'get',
params
});
}
// 用户安装所有
export function getAllInstallBots(params) {
return fetch({
url: `/getAllInstallBots`,
method: 'get',
params
});
}
// 判断用户是否安装此bot
export function judgeIsIntallBot(params) {
return fetch({
url: `/judgeIsIntallBot`,
method: 'get',
params
});
}
// 获取注册的bot详情
export function getRegisterBot(params) {
return fetch({
url: `/getRegisterBot`,
method: 'get',
params
});
}
// 修改注册的bot信息
export function registerUpdateBot(data) {
return fetch({
url: '/registerUpdateBot',
method: 'post',
data: data
});
}
// 更改bot上架信息
export function updateMarketBot(data) {
return fetch({
url: '/updateMarketBot',
method: 'post',
data: data
});
}
// 下架bot
export function downMarket(id, data) {
return fetch({
url: `/downMarket?id=${id}`,
method: 'post',
data: data
});
}
// 卸载已经安装的bot
export function deleteInstallBot(data) {
return fetch({
url: '/deleteInstallBot',
method: 'post',
data: data
});
}
// 取消转让
export function cancelTransferBot(data) {
return fetch({
url: '/cancelTransferBot',
method: 'post',
data: data
});
}

View File

@ -2,6 +2,7 @@ import javaFetch from '../forge/javaFetch';
let settings = localStorage.chromesetting && JSON.parse(localStorage.chromesetting);
let actionUrl = settings && settings.common.softbot;
// let actionUrl = 'http://111.8.36.180:8069';
const service = javaFetch(actionUrl);
export const httpUrl = actionUrl;

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -1,24 +1,81 @@
import { Button, Checkbox, Modal, Radio, Select } from "antd";
import React from "react";
import { useState } from "react";
import style from './index.scss';
import React, { useState, useEffect, useCallback } from "react";
import { Button, Checkbox, message, Modal, Radio, Select } from "antd";
import {getBotDetail, installMarketBot, judgeIsIntallBot} from '../api';
import { getImageUrl } from 'educoder';
import './index.scss';
import axios from "axios";
function SoftBotDEtail(props){
const [detail, setDetail] = useState({name:'bot名称', type: '接口管理', user: '开发者昵称', intro: 'aaaaaaa', iaHas: false, detailIntro: 'aaaaaaa', img: ''});
const [visible, setVisible] = useState(true);
const {match:{params:{id}}, current_user} = props;
const [detail, setDetail] = useState(undefined);
const [visible, setVisible] = useState(false);
const [checkValue, setCheckValue] = useState(1);
const [selectValue, setSelectValue] = useState([]);
const [options, setOptions] = useState(['仓库1', '仓库2仓库2仓库2仓库2仓库2仓库2仓库2', '仓库3', '仓库4', '仓库5']);
const filterOption = options.filter(item=>!selectValue.includes(item));
const [options, setOptions] = useState([]);
const [filterOption, setFilterOption] = useState([]);
const [errTip, setErrTip] = useState(undefined);
// bot
const [isInstall, setIsInstall] = useState(false);
const [reload, setReload] = useState(undefined);
useEffect(()=>{
if(current_user && current_user.login){
//
axios.get(`/users/${current_user.login}/projects.json`,{
params:{
limit: 1000,
page: 1,
category:"manage"
}
}).then(result=>{
if(result && result.data){
setOptions(result.data.projects);
setFilterOption(result.data.projects);
}
}).catch(error=>{
console.log(error);
})}
}, [])
useEffect(()=>{
if(current_user && current_user.login){
// bot
judgeIsIntallBot({
bot_id: id,
user_id: current_user && current_user.user_id
}).then(res=>{
if(res && res.code === 200){
setIsInstall(res.data);
}
})}
}, [reload])
useEffect(()=>{
getBotDetail({
bot_id: id,
user_id: 36480
}).then(res=>{
if(res && res.code === 200){
setDetail(res.data);
}
})
}, [id])
// selectValue
useEffect(()=>{
const ids = selectValue.map(item=>{return item.id});
setFilterOption(options.filter(item=>!ids.includes(item.id)));
}, [selectValue])
function selectChange(e){
let newMap = selectValue;
newMap = newMap.concat(e);
newMap = newMap.concat(options.filter(i=>{return i.id === e})[0]);
setSelectValue(newMap);
}
function click(){
if(detail.iaHas){
if(isInstall){
props.history.push(`/settings/dispositionBot/${id}`)
}else{
// bot
setVisible(true);
@ -27,61 +84,87 @@ function SoftBotDEtail(props){
function deleteSelect(e){
let newMap = selectValue;
newMap = newMap.filter(item=>{return item !== e});
newMap = newMap.filter(item=>{return item.id !== e.id});
setSelectValue(newMap);
}
function okClick(){
setErrTip(undefined);
if(checkValue){
//
if(!selectValue.length){
setErrTip('请至少选择一个仓库');
}else{
installBot();
}
}else{
installBot();
}
}
function installBot(){
const params = {
"user_id":current_user.user_id,
"bot_id":parseInt(id),
"state":1,
"store_list": checkValue ? selectValue.map(item=>{return item.id}) : options.map(item=>{return item.id})
}
installMarketBot(params).then(res=>{
if(res && res.code === 200){
message.success("安装成功");
setVisible(false);
setReload(Math.random());
}
})
}
return <div className="softBotDetailBox">
<div className="botDetailHead">
{detail && <div className="botDetailHead">
<div className="botDetailHeadCont">
<div className="botImgBg"><img src="" alt="" className="botImg"></img></div>
<div className="botImgBg"><img src={getImageUrl(detail.logo)} alt="" className="botImg"></img></div>
<div className="centerBox">
<p className="font-24">{detail.name}</p>
<div className="userBox font-16"><span className="typeBox font-15 mr15">{detail.type}</span>{detail.user}</div>
<div>{detail.intro}</div>
<p className="font-24">{detail.bot_name}</p>
<div className="userBox font-16">{detail.first_func && <span className="typeBox font-15 mr15">{detail.first_func}</span>}{detail.developer_id}</div>
<div>{detail.market_desc}</div>
</div>
<Button type="primary" style={{width: '114px', height: '40px'}} className="font-15" onClick={click}>{detail.iaHas ? '查看详情' : '安装此Bot'}</Button>
<Button type="primary" style={{width: '114px', height: '40px'}} className="font-15" onClick={click}>{isInstall ? '查看详情' : '安装此Bot'}</Button>
</div>
</div>
</div>}
<div className="detailIntroBox">
<div className="detailIntroCont">
<div className="detailIntroTitle font-20 mb10">Bot详细介绍</div>
<div dangerouslySetInnerHTML={{__html: detail.detailIntro}} className="detailIntro font-15"></div>
<div dangerouslySetInnerHTML={{__html: detail && detail.bot_des}} className="detailIntro font-15"></div>
</div>
</div>
<Modal
title={<div><div className="installBotImgBox"><img img={detail.img} alt="" className="installBotImg"/></div><div className="font-18 installBotName">{detail.name}</div></div>}
title={<div><div className="installBotImgBox"><img src={getImageUrl(detail && detail.logo)} alt="" className="installBotImg"/></div><div className="font-18 installBotName">{detail && detail.bot_name}</div></div>}
visible={visible}
onOk={okClick}
onCancel={()=>{setSelectValue([]);setVisible(false)}}
className="installBotModal"
width={735}
closeIcon={<i className="iconfont icon-guanbi font-35 closeIconFont"></i>}
footer={<Button type="primary" style={{width: '385px', height: '42px'}} className="font-15">确认安装</Button>}
footer={<Button type="primary" style={{width: '385px', height: '42px'}} className="font-15" onClick={okClick}>确认安装</Button>}
>
<div className="installTextBox">
<div className="installTil font-18">安装位置</div>
<Radio.Group onChange={(e)=>{setCheckValue(e.target.value)}} value={checkValue}>
<Radio value={0} className="installRadioBox mt10 font-16">安装到所有仓库<br/><span className="font-15 installRadioBoxTip">安装到用户拥有的所有仓库中</span></Radio>
<Radio value={1} className="installRadioBox mt15 font-16">安装到指定仓库<br/><span className="font-15 installRadioBoxTip">请至少选择一个仓库</span></Radio>
<Radio value={1} className="installRadioBox mt15 font-16">安装到指定仓库<br/><span className={`font-15 installRadioBoxTip ${errTip ? 'errTip' :''}`}>请至少选择一个仓库</span></Radio>
</Radio.Group>
{checkValue === 1 && <Select
placeholder="请输入仓库名称"
value={selectValue}
placeholder="请选择仓库"
value={selectValue.map(item=>{return item.id})}
onChange={selectChange}
className="installSelectBox"
dropdownClassName="installDropdownClass"
optionLabelProp="label"
>
{filterOption.map(item=>(<Select.Option key={item} value={item}>{item}</Select.Option>))}
{filterOption.map(item=>(<Select.Option key={item.id} value={item.id}>{item.name}</Select.Option>))}
</Select>}
{selectValue.map((item, index)=>{return <div key={index} className="selectValueBox font-14"><i className="iconfont icon-daimakuicon1 font-14 mr5"></i><span className="selectValue">{item}</span><i className="iconfont icon-guanbi font-12 close ml30" onClick={()=>{deleteSelect(item)}}></i></div>})}
{checkValue === 1 && selectValue.map((item, index)=>{return <div key={index} className="selectValueBox font-14"><i className="iconfont icon-daimakuicon1 font-14 mr5"></i><span className="selectValue">{item.name}</span><i className="iconfont icon-guanbi font-12 close ml30" onClick={()=>{deleteSelect(item)}}></i></div>})}
<div className="installTil font-18 mt20 mb10">权限信息</div>
<div className="mb10"><Checkbox className="greenCol font-16">代码库只读权限</Checkbox></div>
<div className="mb20"><Checkbox className="greenCol font-16">合并请求(PR)读写权限</Checkbox></div>
{detail && <div className="mb10"><Checkbox className="greenCol font-16" checked={detail.limit_and_events.juris_diction_code !== 2}>代码库{detail.limit_and_events.juris_diction_code === 2 ? '无' : detail.limit_and_events.juris_diction_code === 1 ? '读写' : '只读'}权限</Checkbox></div>}
{detail && <div className="mb20"><Checkbox className="greenCol font-16" checked={detail.limit_and_events.juris_diction_pr !== 2}>合并请求(PR){detail.limit_and_events.juris_diction_pr === 2 ? '无' : detail.limit_and_events.juris_diction_pr === 1 ? '读写' : '只读'}权限</Checkbox></div>}
</div>
</Modal>
</div>

View File

@ -19,9 +19,12 @@
.botImgBg{
width: 86px;
height: 86px;
line-height: 86px;
border-radius: 50%;
background-color: yellowgreen;
border: 1px solid white;
img{
max-width: 100%;
}
}
.centerBox{
width: 77%;
@ -59,6 +62,7 @@
.installBotImgBox{
width:100px;
height:100px;
line-height:100px;
background-color:#e9f1ff;
border:3px solid#ffffff;
border-radius: 50%;
@ -66,6 +70,9 @@
top: -50px;
left: 50%;
transform: translate(-50%, 0);
.installBotImg{
max-width: 100%;
}
}
.installBotName{
color:#151d40;
@ -105,6 +112,9 @@
display: inline-block;
margin: 5px 0 0 23px;
color:#99a2af;
&.errTip{
color:#f60011;
}
}
.selectValueBox{
margin: 13px 0 0px 23px;

View File

@ -1,25 +1,48 @@
import React, { useEffect, useState } from "react";
import { Button, Input, Pagination } from "antd";
import { Button, Input, Pagination, Spin } from "antd";
import { getImageUrl } from 'educoder'
import './index.scss';
import { Link } from "react-router-dom";
import {getAllBotCategory} from '../api.js';
import {getAllBotCategory, getContentsLikeNameAndFunc} from '../api.js';
import Nodata from '../../forge/Nodata'
function SoftBot(props){
const {mygetHelmetapi} = props;
const [current, setCurrent] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [pageSize, setPageSize] = useState(12);
const [total, setTotal] = useState(500);
const [activeKet, setActiveKey] = useState(-1);
const [botList, setBotList] = useState([{name: 'hahahah', user: 'aaa908', intro: 'jfsdjhafasdjhg', degree:125, img: '', id: 1}, {name: 'hahahah', user: 'aaa908', intro: 'jfsdjhafasdjhg', degree:125, img: '', id: 2}, {name: 'hahahah', user: 'aaa908', intro: 'jfsdjhafasdjhg', degree:125, img: '', id: 3}, {name: 'hahahah', user: 'aaa908', intro: 'jfsdjhafasdjhg', degree:125, img: '', id: 4}, {name: 'hahahah', user: 'aaa908', intro: 'jfsdjhafasdjhg', degree:125, img: '', id: 5}, {name: 'hahahah', user: 'aaa908', intro: 'jfsdjhafasdjhg', degree:125, img: '', id: 6}])
const [navList, setNavList] = useState([{key: '1', value: '接口管理'}, {key: '2', value: '代码审阅'}])
const [keyWord, setKeyWord] = useState(undefined);
const [botList, setBotList] = useState([])
const [navList, setNavList] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(()=>{
//
getAllBotCategory().then(res=>{
console.log('res', res);
if(res && res.code === 200){
setNavList(res.data && res.data.category_list);
}
})
}, [])
useEffect(()=>{
// softbot
setLoading(true);
getContentsLikeNameAndFunc({
func: activeKet === -1 ? "" : activeKet,
name: keyWord || "",
page_no: current,
page_size: pageSize
}).then(res=>{
if(res && res.code === 200){
setTotal(res.data && res.data.total);
setBotList(res.data && res.data.bot_list);
}
setLoading(false);
})
}, [activeKet, keyWord, pageSize, current])
//
function changeType(key){
setActiveKey(key);
@ -44,24 +67,26 @@ function SoftBot(props){
<div className="botListBox">
<div className="botListNav">
<div className={`navItem font-16 ${activeKet === -1 ? 'active' : ''}`} onClick={()=>changeType(-1)}>全部分类</div>
{navList.map(item=>{return <div className={`navItem font-16 ${activeKet === item.key ? 'active' : ''}`} key={item.key} onClick={()=>changeType(item.key)}>{item.value}</div>})}
{navList.map((item, index)=>{return <div className={`navItem font-16 ${activeKet === item ? 'active' : ''}`} key={index} onClick={()=>changeType(item)}>{item}</div>})}
</div>
<div className="botListCont">
<Input.Search enterButton={<i className="iconfont icon-sousuo_icon"></i>} placeholder="请输入关键字搜索bot" className="botListSearch"/>
<Input.Search enterButton={<i className="iconfont icon-sousuo_icon"></i>} placeholder="请输入关键字搜索bot" className="botListSearch" onSearch={(value)=>{setKeyWord(value)}} allowClear style={{marginLeft: '33px', width: '96.5%'}}/>
<div className="botList">
{botList.map((item, index)=>{
return <div className="oneBotItem mt30" key={index} onClick={()=>{window.location.href=`/softbot/${item.id}`}}>
{!loading && botList && botList.length > 0 && botList.map((item, index)=>{
return <div className="oneBotItem mt30" key={index} onClick={()=>{window.location.href=`/softbot/${item.bot_id}`}}>
<div className="oneItemHead">
<div className="oneBotImgBox"><img src={item.img} alt="" className="oneBotImg"/></div>
<div>
<p className="font-16 oneBotName">{item.name}</p>
<div className="oneBotImgBox"><img src={getImageUrl(item.logo)} alt="" className="oneBotImg"/></div>
<div className="oneBotLine">
<p className="font-16 oneBotName oneBotLine">{item.market_name}</p>
<p>{item.user}</p>
</div>
</div>
<div className="botIntro">{item.intro}</div>
<div className="degreeBox font-16">{item.degree}<span>&nbsp;</span></div>
<div className="botIntro">{item.market_desc}</div>
<div className="degreeBox font-16"><i className="iconfont icon-a-zu1404 mr5 font-16"></i>{item.install_num || 0}<span>&nbsp;</span></div>
</div>
})}
{!loading && botList && !botList.length && <Nodata _html="暂无数据"/>}
{loading && <Spin size="large" className="botLoading"/>}
</div>
</div>
</div>

View File

@ -61,7 +61,7 @@
}
.botListCont{
width: 100%;
padding: 30px 22px 80px 40px;
padding: 30px 22px 80px 0px;
background-image:linear-gradient(180deg,#f3f5f8 0%,#ffffff 100%);
box-shadow:8px 6px 18px rgba(171, 202, 255, 0.24) inset;
.botListSearch{
@ -81,11 +81,12 @@
}
.oneBotItem{
cursor: pointer;
width: 30%;
width: 297px;
background-color:#f4f5f8;
border:1px solid #ffffff;
border-radius:2px;
box-shadow:0px 0px 12px rgba(82, 101, 223, 0.09);
margin-left: 33px;
.oneItemHead{
align-items: center;
background-image: url('../image/botOneBg.png');
@ -97,26 +98,51 @@
.oneBotImgBox{
width: 42px;
height: 42px;
line-height: 42px;
border-radius: 50%;
background-color: yellow;
border:1px solid #ffffff;
margin-right: 15px;
img{
max-width: 100%;
}
}
}
.botIntro{
padding: 14px 17px 10px 14px;
margin: 14px 17px 10px 14px;
color:#8893af;
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
.degreeBox{
color:#151d40;
padding: 0 0 12px 12px;
&>.icon-a-zu1404{
color: #4c5b76;
}
}
}
.botList{
flex-wrap: wrap;
justify-content: space-between;
justify-content: flex-start;
&>.none_panels{
margin: 0 auto;
}
.botLoading{
margin: 200px auto;
}
}
}
.botListPagination{
text-align: right;
}
.oneBotLine{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 0.8;
}