靳炳淑 6 лет назад
Родитель
Сommit
526e4070d7

+ 15 - 2
src/api/codehw.js

@@ -121,11 +121,16 @@ export const getAvailableMirrorList = ({ homeworkId, projectId }) => {
  * @param {string|number} mirrorId
  * @return {Promise<{data:{success:boolean}}>}
  */
-export const makeDeploy = ({ projectId, mirrorId, replicas }) => {
+export const makeDeploy = ({
+  projectId,
+  mirrorId,
+  replicas,
+  deployEnvironment
+}) => {
   console.log(mirrorId);
   return request(`${CODE_HOMEWORK_MODULE}/deploy`, {
     method: "POST",
-    body: { replicas, projectId, mirrorId }
+    body: { replicas, projectId, mirrorId, deployEnvironment }
   });
 };
 
@@ -151,3 +156,11 @@ export const getCodeWorkCommitMsgList = (codeWorkId, groupId) => {
     `${CODE_HOMEWORK_MODULE}/commit?codeWorkId=${codeWorkId}$groupId=${groupId}`
   );
 };
+
+/**
+ * 获取项目的构建镜像记录,用于部署镜像选择
+ * @param {*} projectId
+ */
+export const getBuildImage = projectId => {
+  return request(`${CODE_HOMEWORK_MODULE}/project/${projectId}/build/image`);
+};

+ 304 - 155
src/views/student/Code/ProjectDetail/DeployDetail.vue

@@ -1,92 +1,216 @@
 <template>
-  <div class="data-table">
-    <section>
-      <div class="mirror-subtitle" v-if="deployStatus != 'RUNNING'">
-        选择镜像
-      </div>
-      <div class="select-mirror" v-if="deployStatus != 'RUNNING'">
-        <div class="latest-build">
-          <div
-            class="test-item"
-            :key="`b${item.id}`"
-            v-for="item in latestBuildList"
-          >
-            <div>
-              <b-radio v-model="radio" :native-value="`b${item.id}`"> </b-radio>
-              <strong>构建ID: #</strong> {{ item.id }}
-              <b-tag type="is-success">success</b-tag>
-              <span style="padding-left: 10px">
-                <strong>镜像ID: #</strong> {{ item.mirrorId }}
-              </span>
+  <div class="main">
+    <!--test-->
+    <div class="data-table">
+      <section>
+        <div class="mirror-subtitle" v-if="test.deployStatus != 'RUNNING'">
+          选择Test环境镜像
+        </div>
+        <div class="select-mirror" v-if="test.deployStatus != 'RUNNING'">
+          <div class="latest-build">
+            <div
+              class="test-item"
+              :key="`b${item.id}`"
+              v-for="item in test.latestBuildList"
+            >
+              <div>
+                <b-radio
+                  v-model="test.radio"
+                  :native-value="`b${item.id}`"
+                ></b-radio>
+                <strong>构建ID: #</strong> {{ item.id }}
+                <b-tag type="is-success">success</b-tag>
+                <span style="padding-left: 10px">
+                  <strong>镜像ID: #</strong> {{ item.mirrorId }}
+                </span>
+              </div>
+            </div>
+            <div
+              class="test-item"
+              :key="`d${item.id}`"
+              v-for="item in test.latestDeployList"
+            >
+              <div>
+                <b-radio
+                  v-model="radio"
+                  :native-value="`d${item.id}`"
+                ></b-radio>
+                <strong>部署ID: #</strong> {{ item.id }}
+                <b-tag type="is-success">success</b-tag>
+                <span style="padding-left: 10px">
+                  <strong>镜像ID: #</strong> {{ item.mirrorId }}
+                </span>
+              </div>
             </div>
           </div>
-          <div
-            class="test-item"
-            :key="`d${item.id}`"
-            v-for="item in latestDeployList"
+        </div>
+        <button
+          :class="[
+            'button',
+            'block',
+            'is-link',
+            { 'is-loading': test.isRunning || test.deployButtonDisabled }
+          ]"
+          @click="startDeploy('test')"
+          style="margin-top: 20px;"
+        >
+          开始部署
+        </button>
+        <b-message
+          title="部署进行中..."
+          :active.sync="test.isRunning"
+          type="is-warning"
+          >部署已经开始,一次部署需要大约5-10分钟,请5-10分钟后刷新页面获取部署结果</b-message
+        >
+      </section>
+      <!--部署记录-->
+      <div class="deploy-list" v-if="test.deployInfo">
+        <div class="subtitle">
+          {{ test.isRunning ? "Test当前部署情况" : "Test上次部署结果" }}
+        </div>
+        <div class="deploy-item">本次部署ID: #{{ test.deployInfo.id }}</div>
+        <div class="deploy-item">
+          本次部署镜像ID: #{{ test.deployInfo.mirrorId }}
+        </div>
+        <div class="deploy-item">
+          本次部署创建时间: {{ handleTimeStamp(test.deployInfo.createdAt) }}
+        </div>
+        <div class="deploy-item" v-if="test.deployInfo.endAt">
+          本次部署结束时间: {{ handleTimeStamp(test.deployInfo.endAt) }}
+        </div>
+        <div class="deploy-item">
+          部署结果:
+          <div :class="['tag', type(test.deployInfo.status)]">
+            {{ test.deployInfo.status }}
+          </div>
+        </div>
+        <div class="subtitle">项目部署地址</div>
+        <div class="deploy-item">{{ test.deployInfo.url }}</div>
+        <div class="deploy-item">
+          <div class="subtitle">部署输出信息</div>
+          <a
+            :class="[
+              'button',
+              'is-small',
+              'is-info',
+              { 'is-loading': test.isfetchLog }
+            ]"
+            @click="getDeployLogInfo('test')"
           >
-            <div>
-              <b-radio v-model="radio" :native-value="`d${item.id}`"> </b-radio>
-              <strong>部署ID: #</strong> {{ item.id }}
-              <b-tag type="is-success">success</b-tag>
-              <span style="padding-left: 10px">
-                <strong>镜像ID: #</strong> {{ item.mirrorId }}
-              </span>
-            </div>
+            {{
+              test.unfoldDeployLogInfo ? "收起部署详细信息" : "查看部署详细信息"
+            }}
+          </a>
+          <div class="code-section" v-show="test.unfoldDeployLogInfo">
+            <div class="code-content" v-html="test.deployLog"></div>
           </div>
         </div>
       </div>
-      <button
-        :class="['button', 'block', 'is-link', { 'is-loading': isRunning || deployButtonDisabled }]"
-        @click="startDeploy"
-        style="margin-top: 20px;"
-      >
-        开始部署
-      </button>
-      <b-message
-        title="部署进行中..."
-        :active.sync="isRunning"
-        type="is-warning"
-      >
-        部署已经开始,一次部署需要大约5-10分钟,请5-10分钟后刷新页面获取部署结果
-      </b-message>
-    </section>
-    <!--部署记录-->
-    <div class="deploy-list" v-if="deployInfo">
-      <div class="subtitle">
-        {{ isRunning ? "当前部署情况" : "上次部署结果" }}
-      </div>
-      <div class="deploy-item">本次部署ID: #{{ deployInfo.id }}</div>
-      <div class="deploy-item">本次部署镜像ID: #{{ deployInfo.mirrorId }}</div>
-      <div class="deploy-item">
-        本次部署创建时间: {{ handleTime(deployInfo.createdAt) }}
-      </div>
-      <div class="deploy-item" v-if="deployInfo.endAt">
-        本次部署结束时间: {{ handleTime(deployInfo.endAt) }}
-      </div>
-      <div class="deploy-item">
-        部署结果:
-        <div :class="['tag', type(deployInfo.status)]">
-          {{ deployInfo.status }}
+    </div>
+    <!--prod-->
+    <div class="data-table" :style="{ marginLeft: '20px' }">
+      <section>
+        <div class="mirror-subtitle" v-if="prod.deployStatus != 'RUNNING'">
+          选择Prod环境镜像
         </div>
-      </div>
-      <div class="subtitle">项目部署地址</div>
-      <div class="deploy-item">{{ deployInfo.url }}</div>
-      <div class="deploy-item">
-        <div class="subtitle">部署输出信息</div>
-        <a
+        <div class="select-mirror" v-if="prod.deployStatus != 'RUNNING'">
+          <div class="latest-build">
+            <div
+              class="test-item"
+              :key="`b${item.id}`"
+              v-for="item in prod.latestBuildList"
+            >
+              <div>
+                <b-radio
+                  v-model="prod.radio"
+                  :native-value="`b${item.id}`"
+                ></b-radio>
+                <strong>构建ID: #</strong> {{ item.id }}
+                <b-tag type="is-success">success</b-tag>
+                <span style="padding-left: 10px">
+                  <strong>镜像ID: #</strong> {{ item.mirrorId }}
+                </span>
+              </div>
+            </div>
+            <div
+              class="test-item"
+              :key="`d${item.id}`"
+              v-for="item in prod.latestDeployList"
+            >
+              <div>
+                <b-radio
+                  v-model="radio"
+                  :native-value="`d${item.id}`"
+                ></b-radio>
+                <strong>部署ID: #</strong> {{ item.id }}
+                <b-tag type="is-success">success</b-tag>
+                <span style="padding-left: 10px">
+                  <strong>镜像ID: #</strong> {{ item.mirrorId }}
+                </span>
+              </div>
+            </div>
+          </div>
+        </div>
+        <button
           :class="[
             'button',
-            'is-small',
-            'is-info',
-            { 'is-loading': isfetchLog }
+            'block',
+            'is-link',
+            { 'is-loading': prod.isRunning || prod.deployButtonDisabled }
           ]"
-          @click="getDeployLogInfo"
+          @click="startDeploy('prod')"
+          style="margin-top: 20px;"
         >
-          {{ unfoldDeployLogInfo ? "收起部署详细信息" : "查看部署详细信息" }}</a
+          开始部署
+        </button>
+        <b-message
+          title="部署进行中..."
+          :active.sync="prod.isRunning"
+          type="is-warning"
+          >部署已经开始,一次部署需要大约5-10分钟,请5-10分钟后刷新页面获取部署结果</b-message
         >
-        <div class="code-section" v-show="unfoldDeployLogInfo">
-          <div class="code-content" v-html="deployLog"></div>
+      </section>
+      <!--部署记录-->
+      <div class="deploy-list" v-if="prod.deployInfo">
+        <div class="subtitle">
+          {{ prod.isRunning ? "Prod当前部署情况" : "Prod上次部署结果" }}
+        </div>
+        <div class="deploy-item">本次部署ID: #{{ prod.deployInfo.id }}</div>
+        <div class="deploy-item">
+          本次部署镜像ID: #{{ prod.deployInfo.mirrorId }}
+        </div>
+        <div class="deploy-item">
+          本次部署创建时间: {{ handleTimeStamp(prod.deployInfo.createdAt) }}
+        </div>
+        <div class="deploy-item" v-if="prod.deployInfo.endAt">
+          本次部署结束时间: {{ handleTimeStamp(prod.deployInfo.endAt) }}
+        </div>
+        <div class="deploy-item">
+          部署结果:
+          <div :class="['tag', type(prod.deployInfo.status)]">
+            {{ prod.deployInfo.status }}
+          </div>
+        </div>
+        <div class="subtitle">项目部署地址</div>
+        <div class="deploy-item">{{ prod.deployInfo.url }}</div>
+        <div class="deploy-item">
+          <div class="subtitle">部署输出信息</div>
+          <a
+            :class="[
+              'button',
+              'is-small',
+              'is-info',
+              { 'is-loading': prod.isfetchLog }
+            ]"
+            @click="getDeployLogInfo('prod')"
+          >
+            {{
+              prod.unfoldDeployLogInfo ? "收起部署详细信息" : "查看部署详细信息"
+            }}
+          </a>
+          <div class="code-section" v-show="prod.unfoldDeployLogInfo">
+            <div class="code-content" v-html="prod.deployLog"></div>
+          </div>
         </div>
       </div>
     </div>
@@ -96,28 +220,47 @@
 import {
   // getDeployDetail,
   getDeployLogInfo,
-  getLatestBuildInfoList,
+  // getLatestBuildInfoList,
   makeDeploy,
-  getLatestDeployInfoList
+  getLatestDeployInfoList,
+  getBuildImage
 } from "@/api/codehw";
 
 export default {
   data() {
     return {
-      isActive: false,
-      isRunning: false,
-      deployStatus: "",
-      deployInfo: {},
-      // haveDeployRecord: false,
-      deployLog: "",
-      unfoldDeployLogInfo: false,
-      latestBuildList: [],
-      latestDeployList: [],
-      latestMirrorIdList: [],
-      radio: -1,
-      isfetchLog: false,
-      latestDeployId: 0,
-      deployButtonDisabled: false
+      test: {
+        isActive: false,
+        isRunning: false,
+        deployStatus: "",
+        deployInfo: {},
+        // haveDeployRecord: false,
+        deployLog: "",
+        unfoldDeployLogInfo: false,
+        latestBuildList: [],
+        latestDeployList: [],
+        latestMirrorIdList: [],
+        radio: -1,
+        isfetchLog: false,
+        latestDeployId: 0,
+        deployButtonDisabled: false
+      },
+      prod: {
+        isActive: false,
+        isRunning: false,
+        deployStatus: "",
+        deployInfo: {},
+        // haveDeployRecord: false,
+        deployLog: "",
+        unfoldDeployLogInfo: false,
+        latestBuildList: [],
+        latestDeployList: [],
+        latestMirrorIdList: [],
+        radio: -1,
+        isfetchLog: false,
+        latestDeployId: 0,
+        deployButtonDisabled: false
+      }
     };
   },
   props: {
@@ -131,9 +274,10 @@ export default {
     }
   },
   watch: {
-    projectDetail: function() {
+    projectDetail: function(newVal) {
+      console.log("watch projectDetail", newVal);
       this.getLatestDeployInfo();
-      this.getLatestBuildInfo(this.projectDetail && this.projectDetail.id, 5);
+      this.getLatestBuildInfo(this.projectDetail && this.projectDetail.id);
       this.getLastNDeployInfoList(
         this.projectDetail && this.projectDetail.id,
         5,
@@ -143,7 +287,7 @@ export default {
   },
   mounted() {
     if (this.projectDetail.id) {
-      this.getLatestBuildInfo(this.projectDetail.id, 5);
+      this.getLatestBuildInfo(this.projectDetail.id);
       this.getLastNDeployInfoList(this.projectDetail.id, 5, 1);
       this.getLatestDeployInfo();
     }
@@ -151,39 +295,16 @@ export default {
   methods: {
     //获取最新一次部署信息
     getLatestDeployInfo() {
-      getLatestDeployInfoList(this.projectDetail.id, 1, 0)
-        .then(res => {
-          if (res.data && res.data.length > 0) {
-            this.latestDeployId = res.data[0].id;
-            this.deployInfo = res.data[0];
-            this.deployStatus = res.data[0].status;
-            let isRunning = this.deployStatus == "RUNNING" ? true : false;
-            this.isRunning = isRunning;
-          }
-        })
-        .catch(e => {
-          this.$toast.open({
-            message: e.message || "服务器未知错误",
-            type: "is-danger"
-          });
-        });
+      this.test.deployInfo = this.projectDetail.deploy.latestTestDeploy;
+      this.test.latestDeployId = this.projectDetail.deploy.latestTestDeploy.id;
+      this.test.deployStatus = this.projectDetail.deploy.latestTestDeploy.status;
+      this.test.isRunning = this.test.deployStatus == "RUNNING" ? true : false;
+
+      this.prod.deployInfo = this.projectDetail.deploy.latestProdDeploy;
+      this.prod.latestDeployId = this.projectDetail.deploy.latestProdDeploy.id;
+      this.prod.deployStatus = this.projectDetail.deploy.latestProdDeploy.status;
+      this.prod.isRunning = this.prod.deployStatus == "RUNNING" ? true : false;
     },
-    //获取最新一次部署详细信息
-    // getLatestDeployInfo(deployId) {
-    //   getDeployDetail(deployId)
-    //     .then(res => {
-    //       this.deployInfo = res.data;
-    //       this.deployStatus = res.data.status;
-    //       let isRunning = this.deployStatus == "RUNNING" ? true : false;
-    //       this.isRunning = isRunning;
-    //     })
-    //     .catch(e => {
-    //       this.$toast.open({
-    //         message: e.message || "服务器未知错误",
-    //         type: "is-danger"
-    //       });
-    //     });
-    // },
     //处理时间格式
     handleTime(time) {
       if (!time) {
@@ -191,26 +312,47 @@ export default {
       }
       return time.replace("T", " ") + "ms";
     },
+    //处理时间格式
+    handleTimeStamp(time) {
+      if (!time) {
+        return "";
+      }
+      let date = new Date(time * 1000);
+      return date.toLocaleString();
+    },
     //开始部署
-    startDeploy() {
-      this.deployButtonDisabled = true;
-      if (this.radio == -1) {
+    startDeploy(type) {
+      // prod部署需要test部署成功
+      if (type === "prod") {
+        if (this.test.deployStatus !== "SUCCESS") {
+          this.$toast.open({
+            message: "请先完成test环境的部署",
+            type: "is-danger"
+          });
+          return;
+        }
+      }
+
+      let deployEnvironment = type === "test" ? "TEST" : "PRODUCTION";
+      this[type].deployButtonDisabled = true;
+      if (this[type].radio == -1) {
         this.$toast.open({
           message: "请先选择镜像",
-          type: "is-danger"
+          type: "is-warning"
         });
-        this.deployButtonDisabled = false;
+        this[type].deployButtonDisabled = false;
         return;
       } else {
-        let mirrorId = this.getSelectedMirrorId();
+        let mirrorId = this.getSelectedMirrorId(type);
         //触发部署
         makeDeploy({
           projectId: this.projectDetail.id,
           mirrorId: mirrorId,
-          replicas: 1
+          replicas: 1,
+          deployEnvironment: deployEnvironment
         })
           .then(res => {
-            this.deployButtonDisabled = false;
+            this[type].deployButtonDisabled = false;
             if (res.data.status == "SUCCESS") {
               this.$toast.open({
                 message: "不要重复部署哦~",
@@ -222,12 +364,12 @@ export default {
               message: "开始部署",
               type: "is-success"
             });
-            this.isRunning = true;
-            this.deployInfo = res.data;
-            this.latestDeployId = res.data.id;
+            this[type].isRunning = true;
+            this[type].deployInfo = res.data;
+            this[type].latestDeployId = res.data.id;
           })
           .catch(e => {
-            this.deployButtonDisabled = false;
+            this[type].deployButtonDisabled = false;
             this.$toast.open({
               message: e.message || "服务器未知错误",
               type: "is-danger"
@@ -250,11 +392,12 @@ export default {
         });
     },
     //获取最近n个构建的信息
-    getLatestBuildInfo(projectId, limit) {
-      getLatestBuildInfoList(projectId, limit)
+    getLatestBuildInfo(projectId) {
+      getBuildImage(projectId)
         .then(res => {
-          this.latestBuildList = res.data;
-          // this.latestMirrorIdList = this.latestMirrorIdList.concat(res.data);
+          console.log("getBuildImage", res);
+          this.test.latestBuildList = [res.data.testBuildRecord];
+          this.prod.latestBuildList = [res.data.prodBuildRecord];
         })
         .catch(e => {
           this.$toast.open({
@@ -264,20 +407,20 @@ export default {
         });
     },
     //获取部署日志
-    getDeployLogInfo() {
-      if (this.unfoldDeployLogInfo) {
-        this.unfoldDeployLogInfo = false;
+    getDeployLogInfo(type) {
+      if (this[type].unfoldDeployLogInfo) {
+        this[type].unfoldDeployLogInfo = false;
       } else {
-        let deployId = this.latestDeployId;
-        this.isfetchLog = true;
+        let deployId = this[type].latestDeployId;
+        this[type].isfetchLog = true;
         getDeployLogInfo(deployId)
           .then(res => {
-            this.deployLog = res.data;
-            this.unfoldDeployLogInfo = true;
-            this.isfetchLog = false;
+            this[type].deployLog = res.data;
+            this[type].unfoldDeployLogInfo = true;
+            this[type].isfetchLog = false;
           })
           .catch(e => {
-            this.isfetchLog = false;
+            this[type].isfetchLog = false;
             this.$toast.open({
               message: e.message || "服务器未知错误",
               type: "is-danger"
@@ -298,10 +441,12 @@ export default {
       }
     },
     //选择镜像ID
-    getSelectedMirrorId() {
+    getSelectedMirrorId(type) {
       let list =
-        this.radio[0] == "b" ? this.latestBuildList : this.latestDeployList;
-      let id = this.radio.substring(1);
+        this[type].radio[0] == "b"
+          ? this[type].latestBuildList
+          : this[type].latestDeployList;
+      let id = this[type].radio.substring(1);
       for (let item of list) {
         if (item.id == id) {
           return item.mirrorId;
@@ -313,6 +458,10 @@ export default {
 </script>
 <style lang="scss" scoped>
 @import "../../../../assets/scss/app";
+.main {
+  display: flex;
+  overflow-x: scroll;
+}
 .mirror-subtitle {
   font-size: 1.25rem;
   width: 100%;

+ 1 - 0
src/views/student/Code/ProjectDetail/index.vue

@@ -91,6 +91,7 @@ export default {
     const detail = await getProjectDetail(projectId);
     this.projectDetail = detail.data;
     this.detailLoading = false;
+    console.log("[ProjectDetail]", this.projectDetail);
   }
 };
 </script>

+ 175 - 53
src/views/teacher/Code/ProjectDetail/DeployDetail.vue

@@ -1,44 +1,93 @@
 <template>
-  <div class="data-table">
-    <section>
-      <b-message
-        title="部署进行中..."
-        :active.sync="isRunning"
-        type="is-warning"
-      >
-        部署已经开始,一次部署需要大约5-10分钟,请5-10分钟后刷新页面获取部署结果
-      </b-message>
-    </section>
-    <!--部署记录-->
-    <div class="deploy-list" v-if="deployInfo">
-      <div class="subtitle">
-        {{ isRunning ? "当前部署情况" : "上次部署结果" }}
-      </div>
-      <div class="deploy-item">本次部署ID: #{{ deployInfo.id }}</div>
-      <div class="deploy-item">
-        本次部署创建时间: {{ handleTime(deployInfo.createdAt) }}
-      </div>
-      <div class="deploy-item" v-if="deployInfo.endAt">
-        本次部署结束时间: {{ handleTime(deployInfo.endAt) }}
-      </div>
-      <div class="deploy-item">
-        部署结果:
-        <div :class="['tag', type(deployInfo.status)]">
-          {{ deployInfo.status }}
+  <div class="main-data">
+    <!--test-->
+    <div class="data-table">
+      <section>
+        <b-message
+          title="部署进行中..."
+          :active.sync="test.isRunning"
+          type="is-warning"
+          >部署已经开始,一次部署需要大约5-10分钟,请5-10分钟后刷新页面获取部署结果</b-message
+        >
+      </section>
+      <!--部署记录-->
+      <div class="deploy-list" v-if="test.deployInfo">
+        <div class="subtitle">
+          {{ test.isRunning ? "Test环境当前部署情况" : "Test环境上次部署结果" }}
+        </div>
+        <div class="deploy-item">本次部署ID: #{{ test.deployInfo.id }}</div>
+        <div class="deploy-item">
+          本次部署创建时间: {{ handleTime(test.deployInfo.createdAt) }}
+        </div>
+        <div class="deploy-item" v-if="test.deployInfo.endAt">
+          本次部署结束时间: {{ handleTime(test.deployInfo.endAt) }}
+        </div>
+        <div class="deploy-item">
+          部署结果:
+          <div :class="['tag', type(test.deployInfo.status)]">
+            {{ test.deployInfo.status }}
+          </div>
+        </div>
+        <div class="subtitle">项目部署地址</div>
+        <div class="deploy-item">{{ test.deployInfo.url }}</div>
+        <div class="deploy-item">
+          <div class="subtitle">部署输出信息</div>
+          <a
+            class="button is-small is-info"
+            @click="test.unfoldDeployLogInfo = !test.unfoldDeployLogInfo"
+            >{{
+              test.unfoldDeployLogInfo ? "收起部署详细信息" : "查看部署详细信息"
+            }}</a
+          >
+          <div class="code-section" v-show="test.unfoldDeployLogInfo">
+            <div class="code-content" v-html="test.deployLog"></div>
+          </div>
         </div>
       </div>
-      <div class="subtitle">项目部署地址</div>
-      <div class="deploy-item">{{ deployInfo.url }}</div>
-      <div class="deploy-item">
-        <div class="subtitle">部署输出信息</div>
-        <a
-          class="button is-small is-info"
-          @click="unfoldDeployLogInfo = !unfoldDeployLogInfo"
-        >
-          {{ unfoldDeployLogInfo ? "收起部署详细信息" : "查看部署详细信息" }}</a
+    </div>
+
+    <!--prod-->
+    <div class="data-table" :style="{ marginLeft: '20px' }">
+      <section>
+        <b-message
+          title="部署进行中..."
+          :active.sync="prod.isRunning"
+          type="is-warning"
+          >部署已经开始,一次部署需要大约5-10分钟,请5-10分钟后刷新页面获取部署结果</b-message
         >
-        <div class="code-section" v-show="unfoldDeployLogInfo">
-          <div class="code-content" v-html="deployLog"></div>
+      </section>
+      <!--部署记录-->
+      <div class="deploy-list" v-if="prod.deployInfo">
+        <div class="subtitle">
+          {{ prod.isRunning ? "Prod环境当前部署情况" : "Prod环境上次部署结果" }}
+        </div>
+        <div class="deploy-item">本次部署ID: #{{ prod.deployInfo.id }}</div>
+        <div class="deploy-item">
+          本次部署创建时间: {{ handleTime(prod.deployInfo.createdAt) }}
+        </div>
+        <div class="deploy-item" v-if="prod.deployInfo.endAt">
+          本次部署结束时间: {{ handleTime(prod.deployInfo.endAt) }}
+        </div>
+        <div class="deploy-item">
+          部署结果:
+          <div :class="['tag', type(prod.deployInfo.status)]">
+            {{ prod.deployInfo.status }}
+          </div>
+        </div>
+        <div class="subtitle">项目部署地址</div>
+        <div class="deploy-item">{{ prod.deployInfo.url }}</div>
+        <div class="deploy-item">
+          <div class="subtitle">部署输出信息</div>
+          <a
+            class="button is-small is-info"
+            @click="prod.unfoldDeployLogInfo = !prod.unfoldDeployLogInfo"
+            >{{
+              prod.unfoldDeployLogInfo ? "收起部署详细信息" : "查看部署详细信息"
+            }}</a
+          >
+          <div class="code-section" v-show="prod.unfoldDeployLogInfo">
+            <div class="code-content" v-html="prod.deployLog"></div>
+          </div>
         </div>
       </div>
     </div>
@@ -50,6 +99,25 @@ import { getDeployDetail, getDeployLogInfo } from "@/api/codehw";
 export default {
   data() {
     return {
+      test: {
+        isActive: false,
+        isRunning: false,
+        deployStatus: "",
+        deployInfo: {},
+        haveDeployRecord: false,
+        deployLog: "",
+        unfoldDeployLogInfo: false
+      },
+      prod: {
+        isActive: false,
+        isRunning: false,
+        deployStatus: "",
+        deployInfo: {},
+        haveDeployRecord: false,
+        deployLog: "",
+        unfoldDeployLogInfo: false
+      },
+
       isActive: false,
       isRunning: false,
       deployStatus: "",
@@ -71,30 +139,75 @@ export default {
   },
   watch: {
     projectDetail: function(newVal) {
-      console.log(newVal);
-      //获取最新一次部署详细信息
-      if (newVal.latestDeploy && newVal.latestDeploy.id) {
-        this.haveDeployRecord = true;
-        this.getLatestDeployInfo(newVal.latestDeploy.id);
-        this.getDeployLogInfo(this.projectDetail.latestDeploy.id);
+      console.log("Deploy watch", newVal);
+      //获取最新一次Test部署详细信息
+      if (newVal.deploy.latestTestDeploy && newVal.deploy.latestTestDeploy.id) {
+        this.test.haveDeployRecord = true;
+        this.getLatestDeployInfo(newVal.deploy.latestTestDeploy.id, "test");
+        this.getDeployLogInfo(newVal.deploy.latestTestDeploy.id, "test");
+      }
+
+      //获取最新一次Prod部署详细信息
+      if (newVal.deploy.latestProdDeploy && newVal.deploy.latestProdDeploy.id) {
+        this.test.haveDeployRecord = true;
+        this.getLatestDeployInfo(newVal.deploy.latestProdDeploy.id, "prod");
+        this.getDeployLogInfo(newVal.deploy.latestProdDeploy.id, "prod");
       }
     }
   },
   mounted() {
-    if (this.projectDetail.latestDeploy) {
-      this.getLatestDeployInfo(this.projectDetail.latestDeploy.id);
-      this.getDeployLogInfo(this.projectDetail.latestDeploy.id);
+    console.log("1", this.projectDetail);
+    //获取最新一次Test部署详细信息
+    if (
+      this.projectDetail.deploy &&
+      this.projectDetail.deploy.latestTestDeploy &&
+      this.projectDetail.deploy.latestTestDeploy.id
+    ) {
+      this.test.haveDeployRecord = true;
+      this.getLatestDeployInfo(
+        this.projectDetail.deploy.latestTestDeploy.id,
+        "test"
+      );
+      this.getDeployLogInfo(
+        this.projectDetail.deploy.latestTestDeploy.id,
+        "test"
+      );
+    }
+
+    //获取最新一次Prod部署详细信息
+    if (
+      this.projectDetail.deploy &&
+      this.projectDetail.deploy.latestProdDeploy &&
+      this.projectDetail.deploy.latestProdDeploy.id
+    ) {
+      this.test.haveDeployRecord = true;
+      this.getLatestDeployInfo(
+        this.projectDetail.deploy.latestProdDeploy.id,
+        "prod"
+      );
+      this.getDeployLogInfo(
+        this.projectDetail.deploy.latestProdDeploy.id,
+        "prod"
+      );
     }
   },
   methods: {
     //获取最新一次部署详细信息
-    getLatestDeployInfo(deployId) {
+    getLatestDeployInfo(deployId, type) {
       getDeployDetail(deployId)
         .then(res => {
-          this.deployInfo = res.data;
-          this.deployStatus = res.data.status;
-          let isRunning = this.deployStatus == "RUNNING" ? true : false;
-          this.isRunning = isRunning;
+          if (type === "test") {
+            this.test.deployInfo = res.data;
+            this.test.deployStatus = res.data.status;
+            let isRunning = this.test.deployStatus == "RUNNING" ? true : false;
+            this.test.isRunning = isRunning;
+          }
+          if (type === "prod") {
+            this.prod.deployInfo = res.data;
+            this.prod.deployStatus = res.data.status;
+            let isRunning = this.prod.deployStatus == "RUNNING" ? true : false;
+            this.prod.isRunning = isRunning;
+          }
         })
         .catch(e => {
           this.$toast.open({
@@ -111,10 +224,15 @@ export default {
       return time.replace("T", " ") + "ms";
     },
     //获取部署日志
-    getDeployLogInfo(deployId) {
+    getDeployLogInfo(deployId, type) {
       getDeployLogInfo(deployId)
         .then(res => {
-          this.deployLog = res.data;
+          if (type === "test") {
+            this.test.deployLog = res.data;
+          }
+          if (type === "prod") {
+            this.prod.deployLog = res.data;
+          }
         })
         .catch(e => {
           this.$toast.open({
@@ -140,6 +258,10 @@ export default {
 </script>
 <style lang="scss" scoped>
 @import "../../../../assets/scss/app";
+.main-data {
+  display: flex;
+}
+
 .deploy-list {
   margin-top: 1.5rem;
   .deploy-item {