Переглянути джерело

copy code to new class for modify

mike 6 роки тому
батько
коміт
99d9d916a0

+ 2 - 2
src/app/basicVersion/caseShow/CaseShow.jsx

@@ -120,7 +120,7 @@ class CaseShow extends Component {
                                         <Button
                                             onClick={() => {
                                                 this.props.history.push({
-                                                    pathname: `/common/communication`
+                                                    pathname: `/common/contact`
                                                 })
                                             }}>立即定制</Button>
                                     </Card.Grid>
@@ -287,4 +287,4 @@ class CaseShowDetail extends Component {
             </div>
         )
     }
-}
+}

+ 998 - 0
src/app/basicVersion/deployConfig/DeployConfig.js

@@ -0,0 +1,998 @@
+import React, {Component} from 'react';
+import {Link} from 'react-router-dom';
+import {deployAll, graphqlUrl, storeFile, deployFC} from "../../../config";
+import {ADD_APIGROUP, ADD_APIGWPATH, ADD_DEPLOY, ADD_PROJECT, SHOW_CLOUD} from "../../../gql";
+import {CloudConfig} from "../../../login/CloudConfig";
+import {Layout, Button, message, Modal, Icon, Steps, Row, Col, Radio, Input} from 'antd';
+import {FormattedMessage} from 'react-intl';
+import {request} from 'graphql-request'
+import {idGen, convert_} from "../../../func";
+import axios from 'axios';
+import './index.css';
+import User from "../../user/User";
+
+const {Content} = Layout;
+const Step = Steps.Step;
+const RadioGroup = Radio.Group;
+axios.defaults.withCredentials = true;
+
+class DeployConfig extends Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            userID: props.userID,
+            cloudName: 'tencent',
+            disableDeployButton: false,
+            deployFailed: false,
+            cloudID: '',
+            secretID: '',
+            secretKey: '',
+            appId: '',
+            bucketName: ''
+        };
+
+        console.log(this.state, 'userCustom state')
+    }
+
+    getCloudDetail = (cloudID, secretID, secretKey, appId) => {
+        this.setState({
+            cloudID,
+            secretID,
+            secretKey,
+            appId
+        })
+    };
+
+    componentWillMount() {
+        this._isMounted = true;
+        let {bucketName} = this.props
+        bucketName.then(res => {
+            console.log(res, 'bucketname')
+            this.setState({
+                bucketName: res
+            })
+        })
+    }
+
+    componentWillUnmount() {
+        this._isMounted = false;
+    }
+
+    componentWillReceiveProps(next) {
+        if(next.bucketName !== this.props.bucketName) {
+            let {bucketName} = this.props
+            bucketName.then(res => {
+                console.log(res, 'bucketname')
+                this.setState({
+                    bucketName: res
+                })
+            })
+        }
+    }
+
+    render() {
+        let {userID, cloudID, deployFailed, appId, secretID, secretKey, bucketName} = this.state;
+        let {history} = this.props
+        return (
+            <Content className="content">
+                <div>
+                    <div className="column-menu" onClick={() => {
+                        this.props.backToMe()
+                    }}>
+                        <Icon type="left" style={{color: '#3187FA'}}/>
+                        <FormattedMessage id="back to case show"/>
+                    </div>
+
+                    <Row>
+                        <Col span={9} offset={8}>
+                            <div className='step-kind'>
+                                发布上线
+                            </div>
+                            <Steps direction="vertical" current={6}>
+                                <Step title=<Step1/> />
+                                <Step title=<Step2 getCloudDetail={this.getCloudDetail} userID={userID}/> />
+                                <Step title=
+                                          <Step3
+                                      getPrimaryConfigDetail={this.getPrimaryConfigDetail}
+                                      userID={userID}
+                                      bucketName={bucketName}
+                                      secretID={secretID}
+                                      secretKey={secretKey}
+                                      appId={appId}
+                                      cloudID={cloudID}
+                                      history={history}
+                                />
+                                />
+                                <Step title=<Step4/> />
+                                <Step title=<Step5 bucketName={bucketName} userID={userID}/> />
+                                <Step title=<Step6 bucketName={bucketName} userID={userID}/> />
+
+                            </Steps>
+                        </Col>
+                    </Row>
+                </div>
+            </Content>
+        )
+    }
+}
+
+export default DeployConfig;
+
+const Step1 = (props) => (
+    <div className='step-block'>
+        第一步:注册腾讯云账户
+        <Button style={{marginLeft: 20}}>使用帮助</Button>
+    </div>
+);
+
+class Step2 extends Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            check: 0
+        }
+    }
+
+    render() {
+        let {userID, getCloudDetail} = this.props;
+        let {check} = this.state;
+        // recheck 的作用在于当取消或者保存后重新检测 cloud, 然后通过getCloudDetail传值到父组件
+        return (
+            <div className='step-block'>
+                第二步:填写腾讯云秘钥,一键部署
+                <Button style={{marginLeft: 20}}>使用帮助</Button>
+                <div>
+                    <CloudQueryAndConfig
+                        userID={userID}
+                        getCloudDetail={getCloudDetail}
+                        cloudName='tencent'
+                        check={check}
+                        reCheck={() => {
+                            this.setState({check: check + 1})
+                        }}
+                    />
+                </div>
+            </div>
+        )
+    }
+}
+
+class CloudQueryAndConfig extends Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            cloudName: props.cloudName,
+            userID: props.userID,
+            cloudID: '',
+            secretID: '',
+            secretKey: '',
+            appId: '',
+            visible: false,
+            confirmLoading: false,
+        }
+    }
+
+    searchCloud = () => {
+        this._isMounted = true;
+        let {userID, cloudName} = this.state;
+        // 如果登录,查询该用户是否设置 cloud
+        request(graphqlUrl, SHOW_CLOUD, {user_id: userID}).then(data => {
+                let clouds = data.cloud_by_props.filter(cloud => cloud.cloudName === cloudName);
+                // 如果限制一个云服务商一个 cloud,那么就是clouds[0]
+                if (clouds.length === 1) {
+                    let cloud = clouds[0];
+                    let {id, secretId, secretKey, appId} = cloud;
+                    if (this._isMounted) {
+                        this.setState({
+                            cloudID: id,
+                            secretID: secretId,
+                            secretKey,
+                            appId,
+                        });
+                    }
+                    this.props.getCloudDetail(id, secretId, secretKey, appId);
+                } else if (clouds.length > 1) {
+                    console.log('数据库有多个同一云服务商的 key');
+                } else {
+                    if (this._isMounted) {
+                        console.log('数据库没有云服务商的 key');
+                    }
+                }
+            }
+        )
+    };
+
+    showModal = () => {
+        if (this.state.userID) {
+            this.setState({
+                visible: true,
+            });
+        } else {
+            message.warning('请先登录');
+        }
+    };
+
+    handleCancel = () => {
+        this.setState({
+            visible: false,
+        });
+        this.props.reCheck();
+    };
+
+    componentWillMount() {
+        this.searchCloud();
+        this._isMounted = true;
+    }
+
+    componentWillUnmount() {
+        this._isMounted = false;
+    }
+
+    componentWillReceiveProps(next) {
+        console.log(111)
+        if (this.props.check !== next.check) {
+            this.setState({
+                cloudName: next.cloudName,
+                userID: next.userID,
+            }, this.searchCloud);
+        }
+    }
+
+
+    render() {
+        let {visible, confirmLoading, cloudName} = this.state;
+        // cloudconfig 组件引用外层组件公用,修改时应注意
+        return (
+            <div>
+                <Button type='primary' onClick={this.showModal}>填写秘钥</Button>
+
+                <Modal
+                    title="云服务商秘钥设置"
+                    visible={visible}
+                    confirmLoading={confirmLoading}
+                    footer={null}
+                    onCancel={this.handleCancel}
+                >
+                    <CloudConfig cloudName={cloudName} handleCancel={this.handleCancel}/>
+                </Modal>
+            </div>
+        )
+    }
+}
+
+const Step3 = (props) => (
+    <div className='step-block'>
+        开始部署
+        <div>
+            <NameAndDB
+                userID={props.userID}
+                bucketName={props.bucketName}
+                secretID={props.secretID}
+                secretKey={props.secretKey}
+                appId={props.appId}
+                cloudID={props.cloudID}
+                history={props.history}
+            />
+        </div>
+    </div>
+);
+
+class NameAndDB extends Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            userID: props.userID,
+            visible: false,
+            confirmLoading: false,
+            customName: props.bucketName,
+            dbKind: 'fc-db',
+            host: '',
+            db: '',
+            username: '',
+            password: '',
+            disableDeployButton: false,
+            deployFailed: false
+        }
+    }
+
+    componentWillReceiveProps(next) {
+        if(next.bucketName !== this.props.bucketName) {
+            this.setState({
+                customName: next.bucketName
+            })
+        }
+    }
+
+
+    showModal = () => {
+        if (this.state.userID) {
+            this.setState({
+                visible: true,
+            });
+        } else {
+            message.warning('请先登录');
+        }
+    };
+
+    handleCancel = () => {
+        this.setState({
+            visible: false,
+        });
+    };
+
+    componentWillMount() {
+        this._isMounted = true;
+    }
+
+    componentWillUnmount() {
+        this._isMounted = false;
+    }
+
+    // 首先存储 .edn 文件到 ioobot 的 cos,然后调用下面的 deploy 函数
+    storeEdnAndDeploy = (secretID, secretKey, appId, bucketName, dbKind, userID, admin, username, password, db, host, customName, cloudID) => {
+        // store *.edn to cos
+        secretID = secretID ? secretID : 'AKIDkYBvY0LOJ2bzCDmnMjz4xgFertmVJlVE'
+        secretKey = secretKey ? secretKey : 'zwjKk29TdcYP8g2FG5kCSWmz3wcH92lN'
+        cloudID = cloudID ? cloudID : 'tencent_CloudID'
+        appId = appId ? appId : '1254337200'
+        // mongodb 和 fc-db 区分配置
+        let deployConf = dbKind === 'mongodb' ?
+            ` {:secretId "${secretID}"\n` +
+            ` :secretKey "${secretKey}"\n` +
+            ` :appId "${appId}"\n` +
+            ' :region "ap-beijing" \n' +
+            ' }\n'
+            :
+            ` {:secretId "${secretID}"\n` +
+            ` :secretKey "${secretKey}"\n` +
+            ` :appId "${appId}"\n` +
+            ' :region "ap-beijing"\n' +
+            ' :bucket "fc-db"\n' +
+            ' :trustStore "/etc/ssl/certs/java/cacerts"\n' +
+            ` :fc-db-store "save/${bucketName}.dat"\n` +
+            ' :fc-db-dir "fc-db"\n' +
+            ' :local-tmp-dir "/tmp"\n' +
+            ' :local-db-file "fcdb.dat"\n' +
+            ' :update-tx? true \n' +
+            ' :force-down? true\n' +
+            ' }';
+
+        let a = axios.post(storeFile, {
+            'file-name': `${bucketName}/${dbKind}/${userID}/deploy-conf.edn`,
+            bucket: 'case',
+            cont: deployConf
+        });
+
+        let cont = '{:uri {\n' +
+            `:auth {:admin-db   "${admin}"\n` +
+            ` :u    "${username}"\n` +
+            ` :p   "${password}"\n` +
+            ` :host "${host}"}}\n` +
+            ` :db-name "${db}"}`;
+
+        // fc-db 不用存此文件,故直接返回 status: 200
+        let b = dbKind === 'mongodb' ?
+            axios.post(storeFile, {
+                'file-name': `${bucketName}/${dbKind}/${userID}/mongo-config.edn`,
+                bucket: 'case',
+                cont
+            })
+            :
+            Promise.resolve({status: 200});
+
+        Promise.all([a, b]).then(value => {
+            if (value.every(res => res.status === 200)) {
+                console.log('store file success , start deploying');
+                this.deploy(userID, dbKind, bucketName, customName, cloudID);
+            }
+        });
+    }
+
+    deploy = (userID, dbKind, bucketName, customName, cloudID) => {
+        this._isMounted = true;
+        let _this = this;
+
+        if (bucketName === '') {
+            console.log('state, 没有传值');
+        } else {
+            console.log('开始调用');
+            this.setState({
+                disableDeployButton: true
+            });
+
+            let now = new Date().getTime(),
+                functionName = convert_(userID + '_' + customName),
+                serviceName = functionName,
+                resources = [`${bucketName}/schema.edn`, `${bucketName}/resolve-map.edn`, `${bucketName}/${dbKind}/${userID}/deploy-conf.edn`, `${bucketName}/html/index.html`, `${bucketName}/wx-config.edn`];
+
+            if (dbKind === 'mongodb') {
+                resources.push(`${bucketName}/${dbKind}/${userID}/mongo-config.edn`)
+            }
+
+            console.log('now', now, 'functionName', functionName, 'serviceName', serviceName, 'resources', resources);
+            axios.post(deployAll,
+                {
+                    'fc-name': functionName,
+                    'bucket': dbKind === 'mongodb' ? 'native-fc' : 'fcdb-deploy',
+                    'object-file': 'fc-only.zip',
+                    'res-bucket': 'case',
+                    'resources': resources,
+                    'service-name': serviceName,
+                    'path': "/*"
+                })
+                .then(function (response) {
+                    // 以下操作为写入数据库
+                    console.log('response', response);
+                    if (response['data']['apigw-result'] && response['data']['fc-result']) {
+                        // 处理数据
+                        let result = response['data']['apigw-result'];
+                        let apiData = result['api-info'];
+                        let serviceData = result['service-info'];
+
+                        // 存数据
+                        let pathID = idGen('path'),
+                            groupID = idGen('group'),
+                            deployID = idGen('deploy'),
+                            projectID = idGen('project');
+
+                        let {apiId, path, method} = apiData;
+                        let {serviceName, serviceId, subDomain} = serviceData;
+
+                        let pathVarObj = {
+                            id: idGen('path'),
+                            user_id: userID,
+                            apiGWGroup_id: pathID,
+                            deploy_id: deployID,
+                            apiGWName: functionName,
+                            requestMethod: method,
+                            apiGWPath: path,
+                            apiId: apiId,
+                            apiGWDesc: '',
+                            serviceType: 'SCF',
+                            timeout: 300,
+                            createdAt: now,
+                            updatedAt: ''
+                        };
+
+                        let projectVarObj = {
+                            id: projectID,
+                            projectType: 'case',
+                            cloud_id: cloudID,
+                            user_id: userID,
+                            projectName: functionName,
+                            database_id: '',
+                            apiGWGroup_id: '',
+                            deploy_id: '',
+                            case_id: '',
+                            wxConfig_id: '',
+                            schema_id: '',
+                            createdAt: now,
+                            updatedAt: '',
+                            projectStatus: 'deployed'
+                        };
+
+                        let groupVarObj = {
+                            id: groupID,
+                            cloud_id: cloudID,
+                            user_id: userID,
+                            userStatus: '',
+                            userDomain: '',
+                            groupName: serviceName,
+                            frontType: '',
+                            region: '',
+                            environmentName: '',
+                            defaultDomain: subDomain,
+                            status: '',
+                            serviceId: serviceId,
+                            createdAt: now,
+                            updatedAt: ''
+                        };
+
+                        let deployVarObj = {
+                            id: deployID,
+                            cloud_id: cloudID,
+                            functionName,
+                            cosObjectName: '',
+                            region: '',
+                            cosBucketRegion: '',
+                            description: '',
+                            cosBucketName: '',
+                            vpcId: '',
+                            subnetId: '',
+                            memorySize: 512,
+                            timeout: 300,
+                            handler: '',
+                            serviceName: "",
+                            fc_id: '',
+                            createdAt: now,
+                            updatedAt: ''
+                        };
+
+                        let add_apigwpath = request(graphqlUrl, ADD_APIGWPATH, pathVarObj),
+                            add_project = request(graphqlUrl, ADD_PROJECT, projectVarObj),
+                            add_apigroup = request(graphqlUrl, ADD_APIGROUP, groupVarObj),
+                            add_deploy = request(graphqlUrl, ADD_DEPLOY, deployVarObj);
+
+                        Promise.all([add_apigwpath, add_project, add_apigroup, add_deploy])
+                            .then(value => {
+                                console.log(value);
+
+                                // 展示数据
+                                if (_this._isMounted) {
+                                    _this.setState({
+                                        disableDeployButton: false
+                                    });
+                                }
+
+                                _this.props.history.push({
+                                    pathname: `/common/deploy`,
+                                    state: {
+                                        // 处理传回数据,直接拼接
+                                        url: `http://${subDomain}/test/`
+                                    }
+                                });
+                            })
+                            .catch(err => {
+                                console.log(err);
+                            });
+                    } else {
+                        console.log('deployAll 失败');
+                        _this.setState({
+                            deployFailed: true,
+                            disableDeployButton: false
+                        })
+                    }
+
+                })
+                .catch(function (error) {
+                    console.log('axios error', error);
+                });
+        }
+    };
+
+    render() {
+        let {
+            visible,
+            confirmLoading,
+            userID,
+            dbKind,
+            host,
+            db,
+            username,
+            password,
+            customName,
+            disableDeployButton,
+            deployFailed
+        } = this.state;
+        let {secretID, secretKey, appId, bucketName, cloudID} = this.props
+        return (
+            <div>
+                <Button type='primary' onClick={this.showModal}>开始部署</Button>
+
+                <Modal
+                    title="名称和数据库配置"
+                    visible={visible}
+                    confirmLoading={confirmLoading}
+                    footer={null}
+                    onCancel={this.handleCancel}
+                >
+                    <div>
+                        <div>
+                            <div className={'schema-name'}><FormattedMessage id='Name'/></div>
+                            <div>
+                                <span className='item-title-cloud'><FormattedMessage id='name'/>:</span>
+                                <Input style={{width: 250}} value={this.state.customName}
+                                       onChange={(e) => {
+                                           this.setState({customName: e.target.value})
+                                       }}/>
+                            </div>
+                        </div>
+
+                        <div style={{marginTop: 20}}>
+                            <div className={'schema-name'}><FormattedMessage id='DB Choose'/></div>
+                            <RadioGroup onChange={(e) => {
+                                this.setState({dbKind: e.target.value})
+                            }} value={this.state.dbKind}>
+                                <Radio value='fc-db'>fc-db</Radio>
+                                <Radio value='mongodb'>mongodb</Radio>
+                            </RadioGroup>
+                        </div>
+
+                        {
+                            this.state.dbKind === 'mongodb' ?
+                                <div>
+                                    <div>
+                                        <span className='item-title-cloud'>地址</span>
+                                        <Input style={{width: 250}} value={this.state.host}
+                                               onChange={(e) => {
+                                                   this.setState({host: e.target.value})
+                                               }}
+                                        />
+                                    </div>
+
+                                    <div>
+                                        <span className='item-title-cloud'>数据库名称</span>
+                                        <Input style={{width: 250}} value={this.state.db}
+                                               onChange={(e) => {
+                                                   this.setState({db: e.target.value})
+                                               }}
+                                        />
+                                    </div>
+
+                                    <div>
+                                        <span className='item-title-cloud'>用户名</span>
+                                        <Input style={{width: 250}} value={this.state.username}
+                                               onChange={(e) => {
+                                                   this.setState({username: e.target.value})
+                                               }}
+                                        />
+                                    </div>
+
+                                    <div>
+                                        <span className='item-title-cloud'>密码</span>
+                                        <Input type='password' style={{width: 250}} value={this.state.password}
+                                               onChange={(e) => {
+                                                   this.setState({password: e.target.value})
+                                               }}
+                                        />
+                                    </div>
+                                </div>
+                                :
+                                ''
+                        }
+
+                        {
+                            disableDeployButton ?
+                                '正在部署...'
+                                :
+                                <Button type='primary' onClick={() => {
+                                    this.setState({
+                                        deployFailed: false
+                                    })
+                                    this.storeEdnAndDeploy(secretID, secretKey, appId, bucketName, dbKind, userID, db, username, password, db, host, customName, cloudID)
+                                }}>开始部署</Button>
+
+                        }
+
+                        {
+                            deployFailed?
+                                '部署失败,请稍后重试':''
+                        }
+
+                    </div>
+                </Modal>
+            </div>
+        )
+    }
+}
+
+const Step4 = (props) => (
+    <div className='step-block'>
+        第三步:注册微信公众号/小程序
+        <Button style={{marginLeft: 20}}>使用帮助</Button>
+    </div>
+);
+
+class Step5 extends Component {
+    constructor(props) {
+        super(props)
+        this.state = {
+            visible: false
+        }
+    }
+
+    handleCancel = () => {
+        this.setState({
+            visible: false
+        })
+    }
+
+    render() {
+        let {visible} = this.state
+        let {userID, bucketName} = this.props
+        return (
+            <div className='step-block'>
+                第四步:微信公众号/小程序 后台填写配置
+                <Button style={{marginLeft: 20}}>使用帮助</Button>
+                <div>
+                    <Button type='primary' onClick={() => {
+                        this.setState({visible: true})
+                    }}>填写配置</Button>
+                    <Modal
+                        title="公众号/小程序配置"
+                        visible={visible}
+                        footer={null}
+                        onCancel={this.handleCancel}
+                    >
+                        <Wechat
+                            userID={userID}
+                            bucketName={bucketName}
+                        />
+                    </Modal>
+                </div>
+            </div>
+        )
+    }
+}
+
+// 该组件作用在于 store wx.edn to cos
+class Wechat extends Component {
+    constructor(props) {
+        super(props)
+        this.state = {
+            appID: '',
+            appSecret: '',
+            token: '',
+            url: '',
+            key: '',
+            appid: '',
+            mch: '',
+            nonce: '',
+            body: '',
+            spbill: '',
+            notify: '',
+            attach: '',
+            dbKind: 'fc-db',
+            saving: false,
+            savingCompleted: false
+        }
+    }
+
+    inputChange = (kind) => {
+        return (e) => {
+            this.setState({
+                [kind]: e.target.value
+            })
+        }
+    };
+
+    storeEdn = () => {
+        // store *.edn to cos
+        let {appID, appSecret, token, url, key, appid, mch, nonce, body, spbill, notify, attach, dbKind} = this.state
+        let {userID, bucketName} = this.props
+        let deployConf = `{
+            :wx-server {
+                 :appID "${appID}"                   
+                 :appsecret "${appSecret}"
+                 :enter-url "${url}"
+                 :token "${token}"
+            }
+            :wx-pay {
+                :PAY-API-KEY "${key}"
+                :appid "${appid}"  
+                :attach "${attach}"
+                :mch_id "${mch}"    
+                :nonce_str "${nonce}"
+                :body "${body}"
+                :spbill_create_ip "${spbill}"
+                :notify_url "${notify}"
+            }
+        }`
+
+        axios.post(storeFile, {
+            'file-name': `${bucketName}/${dbKind}/${userID}/wx-config.edn`,
+            bucket: 'case',
+            cont: deployConf
+        }).then(value => {
+            if (value.status === 200) {
+                console.log('store wx file success');
+                this.setState({
+                    saving: false,
+                    savingCompleted: true
+                })
+            }
+        });
+    }
+
+    render() {
+        let {appID, appSecret, token, url, key, appid, mch, nonce, body, spbill, notify, attach, dbKind, saving, savingCompleted} = this.state
+        return (
+            <div>
+                <div style={{marginTop: 15}}>
+                    <div style={{marginBottom: 15}}>
+                        <div>
+                            <span className='cloud-name'><FormattedMessage id='DB Choose'/></span>
+                            <RadioGroup onChange={(e) => {
+                                this.setState({dbKind: e.target.value})
+                            }} value={dbKind}>
+                                <Radio value='fc-db'>fc-db</Radio>
+                                <Radio value='mongodb'>mongodb</Radio>
+                            </RadioGroup>
+                            <span className='cloud-name'>微信开发者配置</span>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>appID:</span>
+                                <Input style={{width: 250}} value={appID} onChange={this.inputChange('appID')}/>
+                            </div>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>appSecret:</span>
+                                <Input type='password' style={{width: 250}} value={appSecret}
+                                       onChange={this.inputChange('appSecret')}/>
+                            </div>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>token:</span>
+                                <Input type='password' style={{width: 250}} value={token}
+                                       onChange={this.inputChange('token')}/>
+                            </div>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>回调域名:</span>
+                                <Input style={{width: 250}} value={url} onChange={this.inputChange('url')}/>
+                            </div>
+                            <span className='cloud-name'>微信支付配置</span>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>key:</span>
+                                <Input style={{width: 250}} value={key} onChange={this.inputChange('key')}/>
+                            </div>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>appid:</span>
+                                <Input style={{width: 250}} value={appid} onChange={this.inputChange('appid')}/>
+                            </div>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>attach:</span>
+                                <Input style={{width: 250}} value={attach} onChange={this.inputChange('attach')}/>
+                            </div>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>商户 id:</span>
+                                <Input style={{width: 250}} value={mch} onChange={this.inputChange('mch')}/>
+                            </div>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>nonce:</span>
+                                <Input style={{width: 250}} value={nonce} onChange={this.inputChange('nonce')}/>
+                            </div>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>body:</span>
+                                <Input style={{width: 250}} value={body} onChange={this.inputChange('body')}/>
+                            </div>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>机器IP:</span>
+                                <Input style={{width: 250}} value={spbill} onChange={this.inputChange('spbill')}/>
+                            </div>
+                            <div style={{marginBottom: 20}}>
+                                <span className='item-title-cloud'>通知域名:</span>
+                                <Input style={{width: 250}} value={notify} onChange={this.inputChange('notify')}/>
+                            </div>
+
+                        </div>
+                        {
+                            saving ?
+                                '保存中,请稍后。。。' :
+                                <Button type='primary' onClick={() => {
+                                    this.storeEdn()
+                                    this.setState({
+                                        saving: true
+                                    })
+                                }}>
+                                    <FormattedMessage id="save"/>
+                                </Button>
+                        }
+                        {
+                            savingCompleted ?
+                                <Icon type="check-circle" theme="twoTone" twoToneColor="#52c41a"/> : ''
+                        }
+                    </div>
+                </div>
+            </div>
+        )
+    }
+}
+
+class Step6 extends Component {
+    constructor(props) {
+        super(props)
+        this.state = {
+            visible: false
+        }
+    }
+
+    handleCancel = () => {
+        this.setState({
+            visible: false
+        })
+    }
+
+    render() {
+        let {visible} = this.state
+        let {userID, bucketName} = this.props
+        return (
+            <div className='step-block'>
+                开始使用
+                <div>
+                    <Button type='primary' onClick={() => {
+                        this.setState({visible: true})
+                    }}>使用</Button>
+                    <Modal
+                        title="公众号/小程序二次部署"
+                        visible={visible}
+                        footer={null}
+                        onCancel={this.handleCancel}
+                    >
+                        <WechatDeploy
+                            userID={userID}
+                            bucketName={bucketName}
+                        />
+                    </Modal>
+                </div>
+            </div>
+        )
+    }
+}
+
+// 该组件作用在于 重新部署 fc
+// 因为需要同名覆盖,所以要求输入同名的函数名
+// 目前不直接在 step before存入共同父组件再传递回来,是因为
+// 考虑到用户刷新,数据将消失
+// 如果需要上述操作,可以考虑限制用户每种案例部署一个,通过查询数据库来实现自动填写
+// 目前的限制一个,在于限制了用户实际部署的,但在前端没有限制个数
+class WechatDeploy extends Component {
+    constructor(props) {
+        super(props)
+        this.state = {
+            dbKind: 'fc-db',
+            customName: props.bucketName,
+            deployButton: true,
+            deploySuccess: false
+        }
+    }
+
+    render() {
+        let {customName, dbKind, deployButton, deploySuccess} = this.state
+        let {bucketName, userID} = this.props;
+        return (
+            <div>
+                <div>
+                    <div className={'schema-name'}><FormattedMessage id='Name'/></div>
+                    <div>
+                        <span className='item-title-cloud'><FormattedMessage id='name'/>:</span>
+                        <Input style={{width: 250}} value={customName}
+                               onChange={(e) => {
+                                   this.setState({customName: e.target.value})
+                               }}/>
+                    </div>
+                </div>
+
+                <div style={{marginTop: 20}}>
+                    <div className={'schema-name'}><FormattedMessage id='DB Choose'/></div>
+                    <RadioGroup onChange={(e) => {
+                        this.setState({dbKind: e.target.value})
+                    }} value={dbKind}>
+                        <Radio value='fc-db'>fc-db</Radio>
+                        <Radio value='mongodb'>mongodb</Radio>
+                    </RadioGroup>
+                </div>
+
+                {
+                    deployButton?
+                        <Button type='primary' onClick={() => {
+                            this.setState({
+                                deployButton: false
+                            })
+                            let functionName = convert_(customName),
+                                resources = [`${bucketName}/schema.edn`, `${bucketName}/resolve-map.edn`, `${bucketName}/${dbKind}/${userID}/deploy-conf.edn`, `${bucketName}/html/index.html`, `${bucketName}/wx-config.edn`];
+
+                            if (dbKind === 'mongodb') {
+                                resources.push(`${bucketName}/${dbKind}/${userID}/mongo-config.edn`)
+                            }
+                            axios.post(deployFC, {
+                                'fc-name': userID + '_' + functionName,
+                                'bucket': dbKind === 'mongodb' ? 'native-fc' : 'fcdb-deploy',
+                                'object-file': 'fc-only.zip',
+                                'res-bucket': 'case',
+                                'resources': resources
+                            }).then(res => {
+                                console.log(res)
+                                this.setState({
+                                    deployButton: true,
+                                    deploySuccess: true
+                                })
+                            })
+                        }}>使用</Button>
+                        :
+                        '正在部署中...'
+                }
+                {
+                    deploySuccess?
+                        '部署成功' : ''
+                }
+            </div>
+        )
+    }
+}

+ 73 - 0
src/app/basicVersion/solution/Solution.jsx

@@ -0,0 +1,73 @@
+import React, {Component} from "react";
+import {SHOW_CASE} from "../../../gql";
+import {Query} from "react-apollo";
+import gql from "graphql-tag";
+import {FormattedMessage} from 'react-intl';
+import {Button, Spin} from 'antd';
+
+class Solution extends Component {
+    constructor(props) {
+        super(props);
+        this.state = {}
+    }
+
+    render() {
+        let caseDetail = this.props.caseContent[0];
+        // console.log('caseDetail',caseDetail);
+
+        return (
+            <div key={caseDetail.id}>
+                <Query query={gql(SHOW_CASE)} variables={{id: caseDetail.id}}>
+                    {
+                        ({loading, error, data}) => {
+                            if (loading) {
+                                return <Spin/>
+                            }
+                            if (error) {
+                                return 'error!';
+                            }
+                            let thisCase = data.case_by_id;
+
+                            return (
+                                <div>
+                                    <div className={'case-show-head'}>{caseDetail.description}</div>
+                                    <div className={'wrapper'}>
+                                        <div>
+                                            <img
+                                                key={thisCase.detailImages[0]}
+                                                src={thisCase.detailImages[0]}
+                                                alt=""
+                                                height="500"
+                                            />
+                                        </div>
+                                        <div className={'right'}>
+                                            <div className="cl-center">
+                                                <div className='cover-div'>
+                                                    <img
+                                                        className='cover-img'
+                                                        src={caseDetail.img}
+                                                        alt={caseDetail.title + '' + caseDetail.description}/>
+                                                </div>
+                                            </div>
+                                            <div className="cl-center">
+                                                微信扫一扫立即体验
+                                            </div>
+                                            <div className="cl-center">
+                                                <Button type="primary"
+                                                        style={{borderRadius: 30}}
+                                                        onClick={() => {
+                                                            this.props.showCustom(caseDetail.schema_id.id);
+                                                        }}><FormattedMessage id='Publish immediately'/></Button>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                            )
+                        }
+                    }
+                </Query>
+            </div>
+        )
+    }
+}
+export default Solution;

+ 226 - 0
src/app/basicVersion/solution/Solutions.jsx

@@ -0,0 +1,226 @@
+import React, {Component} from 'react';
+import {Layout, Card, Button, Avatar, Spin, Icon, Row, Col, notification, Tag} from 'antd';
+import lo from '../../../images/lo.png'
+import './index.css'
+import {graphqlUrl} from "../../../config";
+import {SHOW_ALL_CASE, SHOW_CASE, SEARCH_SCHEMA} from "../../../gql";
+import {FormattedMessage} from 'react-intl';
+import {request} from 'graphql-request'
+import UserCustom from "../deployConfig/DeployConfig";
+import {Query} from "react-apollo";
+import gql from "graphql-tag";
+import {getCookie} from "../../../cookie";
+import Solution from "./Solution";
+
+const {Content} = Layout;
+const {Meta} = Card;
+
+// caseshow 与 usercustom 展示于一个三目运算符
+// 因此刷新 usercustom 将不存在,并且他没有路径
+
+class Solutions extends Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+            examplesIoobot: [],
+            examplesOthers: [],
+            showCustom: false,
+            chosenSchemaID: ''
+        }
+    }
+
+    componentWillMount() {
+        this._isMounted = true;
+        // 查询是否登录
+        let userID = getCookie('user_id');
+        if (userID !== undefined && userID !== '') {
+            this.setState({
+                userID
+            });
+        }
+
+        request(graphqlUrl, SHOW_ALL_CASE, {}).then(data => {
+                let cases = data.case_by_props;
+                // console.log(cases);
+                let examplesIoobot = cases.filter(case1 => case1.user_id.id === 'ioobot');
+                let IooList = this.examplesFilter(examplesIoobot);
+
+                let examplesOthers = cases.filter(case2 => case2.user_id.id !== 'ioobot');
+                let UserList = this.examplesFilter(examplesOthers);
+
+                if (this._isMounted) {
+                    this.setState({
+                        examplesIoobot: IooList,
+                        examplesOthers: UserList
+                    })
+                }
+            }
+        )
+    }
+
+    examplesFilter(example) {
+        // console.log('examples',example);
+        let hash = {}, i = 0, list = [];
+
+        example.forEach(function (item) {
+            let {title} = item;
+            hash[title] ? list[hash[title] - 1].content.push(item) : hash[title] = ++i && list.push({
+                title,
+                content: [item],
+            });
+        });
+
+        // console.log('list',list);
+        return list;
+    }
+
+    componentWillUnmount() {
+        this._isMounted = false;
+    }
+
+    schemaIDChangeBucket = async (schemaID) => {
+        let bucketname = await request(graphqlUrl, SEARCH_SCHEMA, {id: schemaID})
+        console.log(bucketname.schema_by_id.schemaName, 'is schemaName,is equal to bucketName')
+        return bucketname.schema_by_id.schemaName;
+    };
+
+    backToMe = () => {
+        this.setState({
+            showCustom: false
+        })
+    };
+
+    showCustom = (item) => {
+        this.setState({
+            showCustom: true,
+            chosenSchemaID: item
+        })
+    };
+
+    render() {
+        let {userID, showCustom, chosenSchemaID} = this.state;
+
+        return (
+            <div id="example-show">
+                <Layout style={{padding: '24px 48px', minHeight: '300px'}}>
+                    {
+                        !showCustom ?
+                            <div>
+                                <div className={'card card-head'}>
+                                    <Card.Grid className={'card-head-item orange-change'}>
+                                        <p>我们永久无年费 &nbsp;&nbsp;&nbsp;&nbsp; 告别高成本</p>
+                                        <p>省钱、更省心</p>
+                                    </Card.Grid>
+                                    <Card.Grid className={'card-head-item pink-change'}>
+                                        <p>数据完全私有 &nbsp;&nbsp;&nbsp;&nbsp; 安全更可靠</p>
+                                        <p>数据分析图表为您提供更细致的服务</p>
+                                    </Card.Grid>
+                                    <Card.Grid className={'card-head-item blue-change'}>
+                                        <p>模板不满意 &nbsp;&nbsp;&nbsp;&nbsp; 快来定制化吧!</p>
+                                        <p>上手有困难,联系我们即可</p>
+                                        <Button
+                                            onClick={() => {
+                                                this.props.history.push({
+                                                    pathname: `/common/contact`
+                                                })
+                                            }}>立即定制</Button>
+                                    </Card.Grid>
+                                </div>
+                                <div className={'schema-name'}>
+                                    <FormattedMessage id='ioobot case'/>
+                                </div>
+                                <div>
+                                    {
+                                        this.state.examplesIoobot.length === 0 ?
+                                            <Spin/>
+                                            :
+                                            this.state.examplesIoobot.map((item, index) => {
+                                                let exampleList = item.content;
+                                                let gzh = exampleList.filter(case1 => case1.description === '微信公众号');
+                                                let xcx = exampleList.filter(case1 => case1.description === '微信小程序');
+                                                let value = exampleList[0];
+                                                return (
+                                                    <Row key={index} className='card card-case' type="flex"
+                                                         justify="space-around" align="middle">
+                                                        <Col span={6} style={{padding: '20px'}}>
+                                                            <div className="wrap">
+                                                                <div className="case-name">{value.title}</div>
+                                                                <div className="wrapper">
+                                                                    <div>
+                                                                        <div>
+                                                                            <div>模板简介:</div>
+                                                                            <div>{value.detailDescription ? value.detailDescription : '暂无简介'}</div>
+                                                                        </div>
+                                                                        <br/>
+                                                                        <div>
+                                                                            {value.detailAttention ?
+                                                                                <div>适用行业: &nbsp;&nbsp;
+                                                                                    <Tag
+                                                                                        color="blue">{value.detailAttention}</Tag>
+                                                                                </div>
+                                                                                :
+                                                                                ''
+                                                                            }
+                                                                        </div>
+                                                                        <br/>
+                                                                        <div className="left-end">
+                                                                            <div>
+                                                                                <Icon type="mail"/>&nbsp;&nbsp;
+                                                                                {
+                                                                                    value.user_id.email ? value.user_id.email : '该作者未留下联系方式'
+                                                                                }
+                                                                            </div>
+                                                                            <div>
+                                                                                <Icon type="github"/>&nbsp;&nbsp;
+                                                                                {
+                                                                                    value.codeAddress ?
+                                                                                        <a href={value.codeAddress}>查看源码
+                                                                                            可自行修改使用</a>
+                                                                                        :
+                                                                                        '该作者未留下代码仓库地址'
+                                                                                }
+                                                                            </div>
+                                                                        </div>
+                                                                    </div>
+                                                                </div>
+                                                            </div>
+                                                        </Col>
+                                                        <Col span={9} style={{padding: '20px'}}>
+                                                            {gzh.length ?
+                                                                <Solution caseContent={gzh}
+                                                                                showCustom={this.showCustom}/>
+                                                                :
+                                                                <div>敬请期待</div>
+                                                            }
+
+                                                        </Col>
+                                                        <Col span={9} style={{padding: '20px'}}>
+                                                            {xcx.length ?
+                                                                <Solution caseContent={xcx}
+                                                                                showCustom={this.showCustom}/>
+                                                                :
+                                                                <div>敬请期待</div>
+                                                            }
+                                                        </Col>
+                                                    </Row>
+                                                )
+                                            })
+                                    }
+                                </div>
+                            </div>
+                            :
+                            <UserCustom
+                                userID={userID}
+                                bucketName={this.schemaIDChangeBucket(chosenSchemaID)}
+                                history={this.props.history}
+                                backToMe={this.backToMe}
+                            />
+                    }
+                </Layout>
+            </div>
+        )
+    }
+}
+
+export default Solutions;
+

+ 3 - 2
src/language/en_US.js

@@ -161,8 +161,9 @@ const en_US = {
     'qrcode':'qrcode',
 
     'Example': 'Example',
+    'Solution': 'Solution',
     'My deploy': 'My deploy',
-    'Communication': 'Contact us',
+    'Contact': 'Contact us',
     'loading': 'loading...',
     'nothing': 'nothing...',
     'new': 'new!',
@@ -188,4 +189,4 @@ const en_US = {
     'ioobot case': 'ioobot case',
     'other developer case': 'other developer case'
 };
-export default en_US;
+export default en_US;

+ 1 - 0
src/language/zh_CN.js

@@ -162,6 +162,7 @@ const zh_CN = {
     'qrcode':'扫码体验',
 
     'Example': '案例',
+    'Solution': '方案',
     'My deploy': '我的部署',
     'Contact': '联系我们',
     'loading': '加载中...',