This commit is contained in:
2024-03-01 20:28:14 +08:00
commit 076c21dc36
491 changed files with 84482 additions and 0 deletions

View File

@@ -0,0 +1,382 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import './index.scss';
import { Icon, Row, Col, Form, Input, Select, Button, AutoComplete, Tooltip } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
import constants from 'client/constants/variable.js';
const initMap = {
header: [
{
name: '',
value: ''
}
],
cookie: [
{
name: '',
value: ''
}
],
global: [
{
name: '',
value: ''
}
]
};
class ProjectEnvContent extends Component {
static propTypes = {
projectMsg: PropTypes.object,
form: PropTypes.object,
onSubmit: PropTypes.func,
handleEnvInput: PropTypes.func
};
initState(curdata) {
let header = [
{
name: '',
value: ''
}
];
let cookie = [
{
name: '',
value: ''
}
];
let global = [
{
name: '',
value: ''
}
];
const curheader = curdata.header;
const curGlobal = curdata.global;
if (curheader && curheader.length !== 0) {
curheader.forEach(item => {
if (item.name === 'Cookie') {
let cookieStr = item.value;
if (cookieStr) {
cookieStr = cookieStr.split(';').forEach(c => {
if (c) {
c = c.split('=');
cookie.unshift({
name: c[0] ? c[0].trim() : '',
value: c[1] ? c[1].trim() : ''
});
}
});
}
} else {
header.unshift(item);
}
});
}
if (curGlobal && curGlobal.length !== 0) {
curGlobal.forEach(item => {
global.unshift(item);
});
}
return { header, cookie, global };
}
constructor(props) {
super(props);
this.state = Object.assign({}, initMap);
}
addHeader = (value, index, name) => {
let nextHeader = this.state[name][index + 1];
if (nextHeader && typeof nextHeader === 'object') {
return;
}
let newValue = {};
let data = { name: '', value: '' };
newValue[name] = [].concat(this.state[name], data);
this.setState(newValue);
};
delHeader = (key, name) => {
let curValue = this.props.form.getFieldValue(name);
let newValue = {};
newValue[name] = curValue.filter((val, index) => {
return index !== key;
});
this.props.form.setFieldsValue(newValue);
this.setState(newValue);
};
handleInit(data) {
this.props.form.resetFields();
let newValue = this.initState(data);
this.setState({ ...newValue });
}
UNSAFE_componentWillReceiveProps(nextProps) {
let curEnvName = this.props.projectMsg.name;
let nextEnvName = nextProps.projectMsg.name;
if (curEnvName !== nextEnvName) {
this.handleInit(nextProps.projectMsg);
}
}
handleOk = e => {
e.preventDefault();
const { form, onSubmit, projectMsg } = this.props;
form.validateFields((err, values) => {
if (!err) {
let header = values.header.filter(val => {
return val.name !== '';
});
let cookie = values.cookie.filter(val => {
return val.name !== '';
});
let global = values.global.filter(val => {
return val.name !== '';
});
if (cookie.length > 0) {
header.push({
name: 'Cookie',
value: cookie.map(item => item.name + '=' + item.value).join(';')
});
}
let assignValue = {};
assignValue.env = Object.assign(
{ _id: projectMsg._id },
{
name: values.env.name,
domain: values.env.protocol + values.env.domain,
header: header,
global
}
);
onSubmit(assignValue);
}
});
};
render() {
const { projectMsg } = this.props;
const { getFieldDecorator } = this.props.form;
const headerTpl = (item, index) => {
const headerLength = this.state.header.length - 1;
return (
<Row gutter={2} key={index}>
<Col span={10}>
<FormItem>
{getFieldDecorator('header[' + index + '].name', {
validateTrigger: ['onChange', 'onBlur'],
initialValue: item.name || ''
})(
<AutoComplete
style={{ width: '200px' }}
allowClear={true}
dataSource={constants.HTTP_REQUEST_HEADER}
placeholder="请输入header名称"
onChange={() => this.addHeader(item, index, 'header')}
filterOption={(inputValue, option) =>
option.props.children.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1
}
/>
)}
</FormItem>
</Col>
<Col span={12}>
<FormItem>
{getFieldDecorator('header[' + index + '].value', {
validateTrigger: ['onChange', 'onBlur'],
initialValue: item.value || ''
})(<Input placeholder="请输入参数内容" style={{ width: '90%', marginRight: 8 }} />)}
</FormItem>
</Col>
<Col span={2} className={index === headerLength ? ' env-last-row' : null}>
{/* 新增的项中,只有最后一项没有有删除按钮 */}
<Icon
className="dynamic-delete-button delete"
type="delete"
onClick={e => {
e.stopPropagation();
this.delHeader(index, 'header');
}}
/>
</Col>
</Row>
);
};
const commonTpl = (item, index, name) => {
const length = this.state[name].length - 1;
return (
<Row gutter={2} key={index}>
<Col span={10}>
<FormItem>
{getFieldDecorator(`${name}[${index}].name`, {
validateTrigger: ['onChange', 'onBlur'],
initialValue: item.name || ''
})(
<Input
placeholder={`请输入 ${name} Name`}
style={{ width: '200px' }}
onChange={() => this.addHeader(item, index, name)}
/>
)}
</FormItem>
</Col>
<Col span={12}>
<FormItem>
{getFieldDecorator(`${name}[${index}].value`, {
validateTrigger: ['onChange', 'onBlur'],
initialValue: item.value || ''
})(<Input placeholder="请输入参数内容" style={{ width: '90%', marginRight: 8 }} />)}
</FormItem>
</Col>
<Col span={2} className={index === length ? ' env-last-row' : null}>
{/* 新增的项中,只有最后一项没有有删除按钮 */}
<Icon
className="dynamic-delete-button delete"
type="delete"
onClick={e => {
e.stopPropagation();
this.delHeader(index, name);
}}
/>
</Col>
</Row>
);
};
const envTpl = data => {
return (
<div>
<h3 className="env-label">环境名称</h3>
<FormItem required={false}>
{getFieldDecorator('env.name', {
validateTrigger: ['onChange', 'onBlur'],
initialValue: data.name === '新环境' ? '' : data.name || '',
rules: [
{
required: false,
whitespace: true,
validator(rule, value, callback) {
if (value) {
if (value.length === 0) {
callback('请输入环境名称');
} else if (!/\S/.test(value)) {
callback('请输入环境名称');
} else {
return callback();
}
} else {
callback('请输入环境名称');
}
}
}
]
})(
<Input
onChange={e => this.props.handleEnvInput(e.target.value)}
placeholder="请输入环境名称"
style={{ width: '90%', marginRight: 8 }}
/>
)}
</FormItem>
<h3 className="env-label">环境域名</h3>
<FormItem required={false}>
{getFieldDecorator('env.domain', {
validateTrigger: ['onChange', 'onBlur'],
initialValue: data.domain ? data.domain.split('//')[1] : '',
rules: [
{
required: false,
whitespace: true,
validator(rule, value, callback) {
if (value) {
if (value.length === 0) {
callback('请输入环境域名!');
} else if (/\s/.test(value)) {
callback('环境域名不允许出现空格!');
} else {
return callback();
}
} else {
callback('请输入环境域名!');
}
}
}
]
})(
<Input
placeholder="请输入环境域名"
style={{ width: '90%', marginRight: 8 }}
addonBefore={getFieldDecorator('env.protocol', {
initialValue: data.domain ? data.domain.split('//')[0] + '//' : 'http://',
rules: [
{
required: true
}
]
})(
<Select>
<Option value="http://">{'http://'}</Option>
<Option value="https://">{'https://'}</Option>
</Select>
)}
/>
)}
</FormItem>
<h3 className="env-label">Header</h3>
{this.state.header.map((item, index) => {
return headerTpl(item, index);
})}
<h3 className="env-label">Cookie</h3>
{this.state.cookie.map((item, index) => {
return commonTpl(item, index, 'cookie');
})}
<h3 className="env-label">
global
<a
target="_blank"
rel="noopener noreferrer"
href="https://hellosean1025.github.io/yapi/documents/project.html#%E9%85%8D%E7%BD%AE%E7%8E%AF%E5%A2%83"
style={{ marginLeft: 8 }}
>
<Tooltip title="点击查看文档">
<Icon type="question-circle-o" style={{fontSize: '13px'}}/>
</Tooltip>
</a>
</h3>
{this.state.global.map((item, index) => {
return commonTpl(item, index, 'global');
})}
</div>
);
};
return (
<div>
{envTpl(projectMsg)}
<div className="btnwrap-changeproject">
<Button
className="m-btn btn-save"
icon="save"
type="primary"
size="large"
onClick={this.handleOk}
>
</Button>
</div>
</div>
);
}
}
export default Form.create()(ProjectEnvContent);

View File

@@ -0,0 +1,228 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import './index.scss';
import { Icon, Layout, Tooltip, message, Row, Popconfirm } from 'antd';
const { Content, Sider } = Layout;
import ProjectEnvContent from './ProjectEnvContent.js';
import { connect } from 'react-redux';
import { updateEnv, getProject, getEnv } from '../../../../reducer/modules/project';
import EasyDragSort from '../../../../components/EasyDragSort/EasyDragSort.js';
@connect(
state => {
return {
projectMsg: state.project.currProject
};
},
{
updateEnv,
getProject,
getEnv
}
)
class ProjectEnv extends Component {
static propTypes = {
projectId: PropTypes.number,
updateEnv: PropTypes.func,
getProject: PropTypes.func,
projectMsg: PropTypes.object,
onOk: PropTypes.func,
getEnv: PropTypes.func
};
constructor(props) {
super(props);
this.state = {
env: [],
_id: null,
currentEnvMsg: {},
delIcon: null,
currentKey: -2
};
}
initState(curdata, id) {
let newValue = {};
newValue['env'] = [].concat(curdata);
newValue['_id'] = id;
this.setState({
...this.state,
...newValue
});
}
async UNSAFE_componentWillMount() {
this._isMounted = true;
await this.props.getProject(this.props.projectId);
const { env, _id } = this.props.projectMsg;
this.initState(env, _id);
this.handleClick(0, env[0]);
}
componentWillUnmount() {
this._isMounted = false;
}
handleClick = (key, data) => {
this.setState({
currentEnvMsg: data,
currentKey: key
});
};
// 增加环境变量项
addParams = (name, data) => {
let newValue = {};
data = { name: '新环境', domain: '', header: [] };
newValue[name] = [].concat(data, this.state[name]);
this.setState(newValue);
this.handleClick(0, data);
};
// 删除提示信息
showConfirm(key, name) {
let assignValue = this.delParams(key, name);
this.onSave(assignValue);
}
// 删除环境变量项
delParams = (key, name) => {
let curValue = this.state.env;
let newValue = {};
newValue[name] = curValue.filter((val, index) => {
return index !== key;
});
this.setState(newValue);
this.handleClick(0, newValue[name][0]);
newValue['_id'] = this.state._id;
return newValue;
};
enterItem = key => {
this.setState({ delIcon: key });
};
// 保存设置
async onSave(assignValue) {
await this.props
.updateEnv(assignValue)
.then(res => {
if (res.payload.data.errcode == 0) {
this.props.getProject(this.props.projectId);
this.props.getEnv(this.props.projectId);
message.success('修改成功! ');
if(this._isMounted) {
this.setState({ ...assignValue });
}
}
})
.catch(() => {
message.error('环境设置不成功 ');
});
}
// 提交保存信息
onSubmit = (value, index) => {
let assignValue = {};
assignValue['env'] = [].concat(this.state.env);
assignValue['env'].splice(index, 1, value['env']);
assignValue['_id'] = this.state._id;
this.onSave(assignValue);
this.props.onOk && this.props.onOk(assignValue['env'], index);
};
// 动态修改环境名称
handleInputChange = (value, currentKey) => {
let newValue = [].concat(this.state.env);
newValue[currentKey].name = value || '新环境';
this.setState({ env: newValue });
};
// 侧边栏拖拽
handleDragMove = name => {
return (data, from, to) => {
let newValue = {
[name]: data
};
this.setState(newValue);
newValue['_id'] = this.state._id;
this.handleClick(to, newValue[name][to]);
this.onSave(newValue);
};
};
render() {
const { env, currentKey } = this.state;
const envSettingItems = env.map((item, index) => {
return (
<Row
key={index}
className={'menu-item ' + (index === currentKey ? 'menu-item-checked' : '')}
onClick={() => this.handleClick(index, item)}
onMouseEnter={() => this.enterItem(index)}
>
<span className="env-icon-style">
<span className="env-name" style={{ color: item.name === '新环境' && '#2395f1' }}>
{item.name}
</span>
<Popconfirm
title="您确认删除此环境变量?"
onConfirm={e => {
e.stopPropagation();
this.showConfirm(index, 'env');
}}
okText="确定"
cancelText="取消"
>
<Icon
type="delete"
className="interface-delete-icon"
style={{
display: this.state.delIcon == index && env.length - 1 !== 0 ? 'block' : 'none'
}}
/>
</Popconfirm>
</span>
</Row>
);
});
return (
<div className="m-env-panel">
<Layout className="project-env">
<Sider width={195} style={{ background: '#fff' }}>
<div style={{ height: '100%', borderRight: 0 }}>
<Row className="first-menu-item menu-item">
<div className="env-icon-style">
<h3>
环境列表&nbsp;<Tooltip placement="top" title="在这里添加项目的环境配置">
<Icon type="question-circle-o" />
</Tooltip>
</h3>
<Tooltip title="添加环境变量">
<Icon type="plus" onClick={() => this.addParams('env')} />
</Tooltip>
</div>
</Row>
<EasyDragSort data={() => env} onChange={this.handleDragMove('env')}>
{envSettingItems}
</EasyDragSort>
</div>
</Sider>
<Layout className="env-content">
<Content style={{ background: '#fff', padding: 24, margin: 0, minHeight: 280 }}>
<ProjectEnvContent
projectMsg={this.state.currentEnvMsg}
onSubmit={e => this.onSubmit(e, currentKey)}
handleEnvInput={e => this.handleInputChange(e, currentKey)}
/>
</Content>
</Layout>
</Layout>
</div>
);
}
}
export default ProjectEnv;

View File

@@ -0,0 +1,93 @@
.m-env-panel {
// padding-top: 8px;
min-height: 4.68rem;
margin-top: 0;
background-color: #fff;
}
.project-env{
min-height: 4.68rem;
.env-icon-style{
display: flex;
justify-content: space-between;
align-items: center;
.anticon{
font-size: 15px;
}
}
.menu-item{
padding: 0 16px;
font-size: 13px;
line-height: 42px;
height: 42px;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
}
.menu-item-checked{
background-color: #eef7fe;
color: #2395f1;
font-size: 14px;
margin-right: -1px;
border-right: 2px solid #2395f1;
}
.first-menu-item{
background-color: #eceef1;
}
.delete{
font-size: 20px;
top: 8px;
}
.env-content{
border-left: 1px solid #ccc;
}
.ant-menu-item-disabled{
cursor: pointer;
}
.m-empty-prompt{
display: flex;
height: 400px;
span{
margin: auto;
font-size: 16px;
.anticon {
padding-right: 16px;
font-size: 24px;
}
}
}
.env-label{
padding-bottom: 8px;
a {
color: #636363;
}
}
.env-last-row {
display: none;
}
.env-name{
width: 150px;
overflow: hidden;
text-overflow: ellipsis;
}
.btnwrap-changeproject {
text-align: center;
padding: .16rem 0;
background: #fff;
background-color: #fff;
margin: 0 -.4rem;
background-size: 4px 4px;
}
}