Przeglądaj źródła

feat: finish frontend of sign

ArvinQi 6 lat temu
rodzic
commit
636b4930d4

BIN
assets/img/sign/dribbble.png


BIN
assets/img/sign/dribbble@2x.png


BIN
assets/img/sign/github.png


BIN
assets/img/sign/github@2x.png


BIN
assets/img/sign/stackoverflow.png


BIN
assets/img/sign/stackoverflow@2x.png


BIN
assets/img/sign/star-hover.png


BIN
assets/img/sign/star-hover@2x.png


BIN
assets/img/sign/star.png


BIN
assets/img/sign/star@2x.png


BIN
assets/img/sign/zhihu.png


BIN
assets/img/sign/zhihu@2x.png


+ 75 - 0
components/multi-uploader.vue

@@ -0,0 +1,75 @@
+<template>
+  <div class="multi-uploader">
+    <el-upload
+      action="/upload_image"
+      list-type="picture-card"
+      :file-list="fileList"
+      :on-preview="handlePictureCardPreview"
+      :on-remove="handleRemove"
+      :on-success="handleSuccess"
+    >
+      <i class="el-icon-plus"></i>
+    </el-upload>
+    <el-dialog :visible.sync="dialogVisible">
+      <img width="100%" :src="dialogImageUrl" alt />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "multi-uploader",
+  props: {
+    value: Array
+  },
+  model: {
+    prop: "value",
+    event: "change"
+  },
+  components: {},
+  data() {
+    return {
+      uploading: false,
+      fileList: [],
+      dialogImageUrl: "",
+      dialogVisible: false
+    };
+  },
+  computed: {},
+  mounted() {
+    this.fileList = this.value;
+  },
+  methods: {
+    handleRemove(file, fileList) {
+      console.log(file, fileList);
+      this.handleChange(fileList);
+    },
+    handlePictureCardPreview(file) {
+      this.dialogImageUrl = file.url;
+      this.dialogVisible = true;
+    },
+    handleSuccess(response, file, fileList) {
+      console.log(response, file, fileList);
+      this.handleChange(fileList);
+    },
+    handleChange(fileList) {
+      const list = [];
+      fileList.map(file => {
+        list.push({
+          name: file.name,
+          url: file.response ? file.response.filename : file.url
+        });
+      });
+      console.log(list, fileList);
+      this.$emit("change", list);
+    }
+  }
+};
+</script>
+
+<style lang="scss">
+.multi-uploader {
+  position: relative;
+  background: #fff;
+}
+</style>

+ 200 - 3
components/sign/education.vue

@@ -1,11 +1,208 @@
 <template>
-  <div>目前SSR未有页面</div>
+  <div class="education">
+    <header>
+      <h5>教育经历</h5>
+      <span>
+        <el-button @click="handleAdd" type="text" icon="el-icon-plus"></el-button>
+      </span>
+    </header>
+    <div v-if="education.length > 0">
+      <template v-for="(item, idx) in education">
+        <div v-if="editingItem.indexOf(idx) < 0" :key="item.company" class="show">
+          <h4>
+            <span>{{`${item.start} - ${item.end} ${item.company} ${item.position}`}}</span>
+            <el-button @click="editItem(idx)" type="text">编辑</el-button>
+          </h4>
+          <p>{{item.des}}</p>
+        </div>
+        <div v-else :key="item.company" class="edit">
+          <el-form ref="form" :rules="rules" :model="education[idx]" label-width="147px">
+            <div class="header">
+              <el-date-picker v-model="education[idx].start" type="date" placeholder="开始时间"></el-date-picker>
+              <span class="to">至</span>
+              <el-date-picker v-model="education[idx].end" type="date" placeholder="结束时间"></el-date-picker>
+              <el-input
+                :style="{width: '202px'}"
+                v-model="education[idx].company"
+                placeholder="学校名称"
+              ></el-input>
+              <el-select v-model="education[idx].position" placeholder="选择专业">
+                <el-option label="区域一" value="shanghai"></el-option>
+                <el-option label="区域二" value="beijing"></el-option>
+              </el-select>
+              <span class="opts">
+                <el-button type="danger" @click="handleDelete(idx)">删除</el-button>
+                <el-button type="info" @click="handleCancel(idx)">取消</el-button>
+                <el-button type="primary" @click="onSubmit(idx)">确认</el-button>
+              </span>
+            </div>
+            <div class="content">
+              <el-input
+                type="textarea"
+                :rows="7"
+                placeholder="教育经历文字说明,不得低于15个字符"
+                v-model="education[idx].des"
+              ></el-input>
+              <uploader :imageUrl="education[idx].imageUrl" title="工作证明" @change="handleImageUrl"></uploader>
+            </div>
+            <footer>
+              <p>学信网在线验证报告, 例如:https://www.proginn.com</p>
+              <p>注:学历证明可以是毕业证图片或学信网在线验证报告(二选一即可)</p>
+            </footer>
+          </el-form>
+        </div>
+      </template>
+    </div>
+    <div v-else class="empty">点击右上角“添加”按钮添加教育经历</div>
+  </div>
 </template>
 
 <script>
+import uploader from "@/components/uploader";
 export default {
-}
+  data() {
+    return {
+      // editing: true,
+      editingItem: [],
+      rules: {
+        name: ""
+      },
+      init: {
+        imageUrl: "",
+        start: "",
+        end: "",
+        company: "",
+        position: "",
+        des: ""
+      },
+      education: [
+        // {
+        //   imageUrl: "",
+        //   start: "2019-01-02",
+        //   end: "2019-01-02",
+        //   company: "程序员客栈",
+        //   position: "高级产品经理",
+        //   des:
+        //     "主要负责程序员客栈“雇佣直通车、1980服务、云端项目、雇佣项目“项目前后端开发,参与整个项目的设计、需求讨论、代码开发、联调测试及系统维护迭代。 【主要工作成就】:解决“雇佣直通车”项目,系统智能自动匹配算法问题。"
+        // }
+      ],
+      current: null
+    };
+  },
+  components: {
+    uploader
+  },
+  methods: {
+    onSubmit(idx) {
+      console.log("submit!", this.form);
+      this.education.push(this.form);
+    },
+    handleAdd() {
+      this.education.push(this.init);
+      this.editingItem.push(this.education.length - 1);
+    },
+    handleImageUrl(url) {
+      this.form.imageUrl = url;
+    },
+    handleDelete(idx) {
+      this.education.splice(this.education.indexOf(this.current), 1);
+    },
+    handleCancel(idx) {
+      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+    },
+    editItem(idx) {
+      this.editingItem.push(idx);
+    }
+  }
+};
 </script>
 
-<style>
+<style lang="scss" scoped>
+.education {
+  header .el-icon-plus {
+    font-size: 18px;
+  }
+  .edit {
+    padding: 20px;
+    > form {
+      .opts {
+        float: right;
+      }
+      .el-select,
+      .el-input {
+        width: 136px;
+        margin-right: 10px;
+        .el-input--suffix .el-input__inner {
+          padding-right: 0;
+        }
+      }
+      .to {
+        margin-right: 10px;
+      }
+      .times {
+        .el-checkbox {
+          width: 88px;
+        }
+        .el-input {
+          width: 136px;
+        }
+      }
+      .content {
+        display: flex;
+        justify-content: space-between;
+        align-items: flex-start;
+        margin-top: 10px;
+        .el-textarea {
+          display: flex;
+          width: 766px;
+          height: 162px;
+        }
+      }
+    }
+  }
+  .show {
+    padding: 23px 33px 23px 20px;
+    border-bottom: 1px solid #ebeef5;
+    &:last-of-type {
+      border: 0;
+    }
+    h4 {
+      display: flex;
+      justify-content: space-between;
+      height: 44px;
+      font-size: 14px;
+      font-family: PingFangSC-Medium;
+      font-weight: 500;
+      color: #308eff;
+      line-height: 44px;
+    }
+    p {
+      margin-top: 8px;
+      font-size: 14px;
+      font-family: PingFangSC-Regular;
+      font-weight: 400;
+      color: rgba(102, 102, 102, 1);
+      line-height: 24px;
+    }
+  }
+
+  .empty {
+    margin: 112px auto 104px;
+    font-size: 27px;
+    font-family: PingFangSC-Regular;
+    font-weight: 400;
+    text-align: center;
+    color: rgba(205, 205, 205, 1);
+    line-height: 38px;
+  }
+  footer p {
+    margin-top: 15px;
+    width: 766px;
+    font-size: 12px;
+    font-family: PingFangSC-Regular;
+    font-weight: 400;
+    color: rgba(145, 154, 167, 1);
+    line-height: 17px;
+  }
+}
 </style>

+ 115 - 54
components/sign/experience.vue

@@ -2,50 +2,76 @@
   <div class="info">
     <header>
       <h5>工作经历</h5>
-    </header>
-    <div v-if="experience.length" class="show">
-      <div v-for="item in experience" :key="item.company">
-        <h4>
-          <span>{{`${item.start} - ${item.end} ${item.company} ${item.position}`}}</span>
-          <el-button type="text">编辑</el-button>
-        </h4>
-        <p>{{item.des}}</p>
-      </div>
-    </div>
-    <div v-if="editing" class="edit">
-      <el-form ref="form" :rules="rules" :model="form" label-width="147px">
-        <div class="header">
-          <el-date-picker v-model="form.start" type="date" placeholder="开始时间"></el-date-picker>
-          <span class="to">至</span>
-          <el-date-picker v-model="form.end" type="date" placeholder="结束时间"></el-date-picker>
-          <el-input :style="{width: '202px'}" v-model="form.company" placeholder="请输入公司名称"></el-input>
-          <el-select v-model="form.position" placeholder="选择职位">
-            <el-option label="区域一" value="shanghai"></el-option>
-            <el-option label="区域二" value="beijing"></el-option>
-          </el-select>
-          <span v-if="editing" class="opts">
-            <el-button type="danger" @click="handleDelete">删除</el-button>
-            <el-button type="info" @click="editing = false">取消</el-button>
-            <el-button type="primary" @click="onSubmit">确认</el-button>
+      <span>
+        <el-button v-if="experience.length > 0" @click="rankDialog = true" type="text">设置优先展示</el-button>
+        <el-dialog title="设置优先展示" :visible.sync="rankDialog" :before-close="handleRankClose">
+          <el-form ref="form" :model="rankForm" label-width="147px">
+            <el-form-item label="优先展示" prop="name">
+              <el-select v-model="rankForm.first" placeholder="选择优先展示">
+                <el-option
+                  v-for="(item, idx) in experience"
+                  :label="item.company"
+                  :value="idx"
+                  :key="item.company"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-form>
+          <span slot="footer" class="dialog-footer">
+            <el-button @click="rankDialog = false">取 消</el-button>
+            <el-button type="primary" @click="handleRank">确 定</el-button>
           </span>
-          <div v-else class="opts">
-            <el-button type="primary" @click="editing = true">编辑</el-button>
-          </div>
+        </el-dialog>
+        <el-button @click="handleAdd" type="text" icon="el-icon-plus"></el-button>
+      </span>
+    </header>
+    <div v-if="experience.length > 0">
+      <template v-for="(item, idx) in experience">
+        <div v-if="editingItem.indexOf(idx) < 0" :key="item.company" class="show">
+          <h4>
+            <span>{{`${item.start} - ${item.end} ${item.company} ${item.position}`}}</span>
+            <el-button @click="editItem(idx)" type="text">编辑</el-button>
+          </h4>
+          <p>{{item.des}}</p>
         </div>
-        <div class="content">
-          <el-input
-            type="textarea"
-            :rows="7"
-            placeholder="请从主要工作内容、成就等方面,描述你的工作经历,字数不少于60字符"
-            v-model="form.des"
-          ></el-input>
-          <uploader :imageUrl="form.imageUrl" title="工作证明" @change="handleImageUrl"></uploader>
+        <div v-else :key="item.company" class="edit">
+          <el-form ref="form" :rules="rules" :model="experience[idx]" label-width="147px">
+            <div class="header">
+              <el-date-picker v-model="experience[idx].start" type="date" placeholder="开始时间"></el-date-picker>
+              <span class="to">至</span>
+              <el-date-picker v-model="experience[idx].end" type="date" placeholder="结束时间"></el-date-picker>
+              <el-input
+                :style="{width: '202px'}"
+                v-model="experience[idx].company"
+                placeholder="请输入公司名称"
+              ></el-input>
+              <el-select v-model="experience[idx].position" placeholder="选择职位">
+                <el-option label="区域一" value="shanghai"></el-option>
+                <el-option label="区域二" value="beijing"></el-option>
+              </el-select>
+              <span class="opts">
+                <el-button type="danger" @click="handleDelete(idx)">删除</el-button>
+                <el-button type="info" @click="handleCancel(idx)">取消</el-button>
+                <el-button type="primary" @click="onSubmit(idx)">确认</el-button>
+              </span>
+            </div>
+            <div class="content">
+              <el-input
+                type="textarea"
+                :rows="7"
+                placeholder="请从主要工作内容、成就等方面,描述你的工作经历,字数不少于60字符"
+                v-model="experience[idx].des"
+              ></el-input>
+              <uploader :imageUrl="experience[idx].imageUrl" title="工作证明" @change="handleImageUrl"></uploader>
+            </div>
+            <footer>
+              <p>注:有效的工作证明包括:工牌/入职通知邮件/在职证明/公司邮箱截图/公司获奖证书/钉钉截图/离职证明/社保公积金证明等(其中之一即可,截图中需同时出现公司信息和个人信息,才能作为有效工作证明,并与目前公司相一致)</p>
+            </footer>
+          </el-form>
         </div>
-        <footer>
-          <p>注:有效的工作证明包括:工牌/入职通知邮件/在职证明/公司邮箱截图/公司获奖证书/钉钉截图/离职证明/社保公积金证明等(其中之一即可,截图中需同时出现公司信息和个人信息,才能作为有效工作证明,并与目前公司相一致)</p>
-        </footer>
-      </el-form>
+      </template>
     </div>
+    <div v-else class="empty">点击右上角“添加”按钮添加工作经历</div>
   </div>
 </template>
 
@@ -54,11 +80,12 @@ import uploader from "@/components/uploader";
 export default {
   data() {
     return {
-      editing: true,
+      // editing: true,
+      editingItem: [],
       rules: {
         name: ""
       },
-      form: {
+      init: {
         imageUrl: "",
         start: "",
         end: "",
@@ -67,32 +94,54 @@ export default {
         des: ""
       },
       experience: [
-        {
-          imageUrl: "",
-          start: "2019-01-02",
-          end: "2019-01-02",
-          company: "程序员客栈",
-          position: "高级产品经理",
-          des:
-            "主要负责程序员客栈“雇佣直通车、1980服务、云端项目、雇佣项目“项目前后端开发,参与整个项目的设计、需求讨论、代码开发、联调测试及系统维护迭代。 【主要工作成就】:解决“雇佣直通车”项目,系统智能自动匹配算法问题。"
-        }
+        // {
+        //   imageUrl: "",
+        //   start: "2019-01-02",
+        //   end: "2019-01-02",
+        //   company: "程序员客栈",
+        //   position: "高级产品经理",
+        //   des:
+        //     "主要负责程序员客栈“雇佣直通车、1980服务、云端项目、雇佣项目“项目前后端开发,参与整个项目的设计、需求讨论、代码开发、联调测试及系统维护迭代。 【主要工作成就】:解决“雇佣直通车”项目,系统智能自动匹配算法问题。"
+        // }
       ],
-      current: null
+      current: null,
+      rankDialog: false,
+      rankForm: {
+        first: ""
+      }
     };
   },
   components: {
     uploader
   },
   methods: {
-    onSubmit() {
+    onSubmit(idx) {
       console.log("submit!", this.form);
       this.experience.push(this.form);
     },
+    handleRankClose() {
+      this.rankForm = {
+        first: ""
+      };
+    },
+    handleRank() {
+      this.rankDialog = false;
+    },
+    handleAdd() {
+      this.experience.push(this.init);
+      this.editingItem.push(this.experience.length - 1);
+    },
     handleImageUrl(url) {
       this.form.imageUrl = url;
     },
-    handleDelete() {
+    handleDelete(idx) {
       this.experience.splice(this.experience.indexOf(this.current), 1);
+    },
+    handleCancel(idx) {
+      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+    },
+    editItem(idx) {
+      this.editingItem.push(idx);
     }
   }
 };
@@ -100,6 +149,9 @@ export default {
 
 <style lang="scss" scoped>
 .info {
+  header .el-icon-plus {
+    font-size: 18px;
+  }
   .edit {
     padding: 20px;
     > form {
@@ -163,6 +215,15 @@ export default {
       line-height: 24px;
     }
   }
+  .empty {
+    margin: 112px auto 104px;
+    font-size: 27px;
+    font-family: PingFangSC-Regular;
+    font-weight: 400;
+    text-align: center;
+    color: rgba(205, 205, 205, 1);
+    line-height: 38px;
+  }
   footer p {
     margin-top: 15px;
     width: 766px;

+ 1 - 1
components/sign/info.vue

@@ -140,7 +140,7 @@ export default {
         dailyRate: "312",
         workingTime: "123"
       },
-      editing: false
+      editing: true
     };
   },
   methods: {

+ 189 - 3
components/sign/skills.vue

@@ -1,11 +1,197 @@
 <template>
-  <div>目前SSR未有页面</div>
+  <div class="skill">
+    <header>
+      <h5>技能</h5>
+      <span>
+        <el-button @click="handleAdd" type="text" icon="el-icon-plus"></el-button>
+      </span>
+    </header>
+    <div v-if="skills.length > 0">
+      <template v-for="(item, idx) in skills">
+        <div v-if="editingItem.indexOf(idx) < 0" :key="item.name" class="show">
+          <h4>
+            <span>{{`技能名称: ${item.name} 经验自评:${item.level}分 1分为新入门,5分为满分`}}</span>
+            <el-button @click="editItem(idx)" type="text">编辑</el-button>
+          </h4>
+        </div>
+        <div v-else :key="item.name" class="edit">
+          <el-form ref="form" :rules="rules" :model="skills[idx]" label-width="80px">
+            <div class="header">
+              <el-form-item label="技能名称" prop="name">
+                <el-input
+                  :style="{width: '250px'}"
+                  v-model="skills[idx].name"
+                  placeholder="填写单个技能全名"
+                ></el-input>
+              </el-form-item>
+              <el-form-item label="经验自评" prop="level">
+                <el-select :style="{width: '130px'}" v-model="skills[idx].level" placeholder="选择分数">
+                  <el-option v-for="item in 5" :label="`${item}分`" :key="item" value="item"></el-option>
+                </el-select>
+              </el-form-item>
+              <span class="tips">1分为新入门,5分为满分</span>
+              <span class="opts">
+                <el-button type="danger" @click="handleDelete(idx)">删除</el-button>
+                <el-button type="info" @click="handleCancel(idx)">取消</el-button>
+                <el-button type="primary" @click="onSubmit(idx)">确认</el-button>
+              </span>
+            </div>
+          </el-form>
+        </div>
+      </template>
+    </div>
+    <div v-else class="empty">点击右上角“添加”按钮添加技能</div>
+  </div>
 </template>
 
 <script>
+import uploader from "@/components/uploader";
 export default {
-}
+  data() {
+    return {
+      // editing: true,
+      editingItem: [],
+      rules: {
+        name: [{ required: true, message: "请输入技能全名", trigger: "blur" }]
+      },
+      init: {
+        name: "",
+        level: ""
+      },
+      skills: [
+        // {
+        //   name: "Javscript",
+        //   level: "5"
+        // }
+      ],
+      current: null
+    };
+  },
+  components: {
+    uploader
+  },
+  methods: {
+    onSubmit(idx) {
+      console.log("submit!", this.form);
+      this.skills.push(this.form);
+    },
+    handleAdd() {
+      this.skills.push(this.init);
+      this.editingItem.push(this.skills.length - 1);
+    },
+    handleImageUrl(url) {
+      this.form.imageUrl = url;
+    },
+    handleDelete(idx) {
+      this.skills.splice(this.skills.indexOf(this.current), 1);
+    },
+    handleCancel(idx) {
+      console.log(idx, this.skills[idx]);
+      if (!this.skills[idx].name) {
+        this.handleDelete(idx);
+      }
+      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+    },
+    editItem(idx) {
+      this.editingItem.push(idx);
+    }
+  }
+};
 </script>
 
-<style>
+<style lang="scss" scoped>
+.skill {
+  header .el-icon-plus {
+    font-size: 18px;
+  }
+  .edit {
+    padding: 20px;
+    .header {
+      display: flex;
+      align-items: center;
+      .tips {
+        margin-right: 5px;
+      }
+    }
+    > form {
+      .opts {
+        float: right;
+      }
+      .el-select,
+      .el-input {
+        width: 136px;
+        margin-right: 10px;
+        .el-input--suffix .el-input__inner {
+          padding-right: 0;
+        }
+      }
+      .to {
+        margin-right: 10px;
+      }
+      .times {
+        .el-checkbox {
+          width: 88px;
+        }
+        .el-input {
+          width: 136px;
+        }
+      }
+      .content {
+        display: flex;
+        justify-content: space-between;
+        align-items: flex-start;
+        margin-top: 10px;
+        .el-textarea {
+          display: flex;
+          width: 766px;
+          height: 162px;
+        }
+      }
+    }
+  }
+  .show {
+    padding: 23px 33px 23px 20px;
+    border-bottom: 1px solid #ebeef5;
+    &:last-of-type {
+      border: 0;
+    }
+    h4 {
+      display: flex;
+      justify-content: space-between;
+      height: 44px;
+      font-size: 14px;
+      font-family: PingFangSC-Medium;
+      font-weight: 500;
+      /* color: #308eff; */
+      line-height: 44px;
+    }
+    p {
+      margin-top: 8px;
+      font-size: 14px;
+      font-family: PingFangSC-Regular;
+      font-weight: 400;
+      color: rgba(102, 102, 102, 1);
+      line-height: 24px;
+    }
+  }
+
+  .empty {
+    margin: 112px auto 104px;
+    font-size: 27px;
+    font-family: PingFangSC-Regular;
+    font-weight: 400;
+    text-align: center;
+    color: rgba(205, 205, 205, 1);
+    line-height: 38px;
+  }
+  footer p {
+    margin-top: 15px;
+    width: 766px;
+    font-size: 12px;
+    font-family: PingFangSC-Regular;
+    font-weight: 400;
+    color: rgba(145, 154, 167, 1);
+    line-height: 17px;
+  }
+}
 </style>

+ 169 - 3
components/sign/social.vue

@@ -1,11 +1,177 @@
 <template>
-  <div>目前SSR未有页面</div>
+  <div class="info">
+    <header>
+      <h5>专业社区影响力</h5>
+    </header>
+    <div class="edit">
+      <el-form ref="form" :rules="rules" :model="social" label-width="130px">
+        <div class="line">
+          <img
+            class="prefix-icon"
+            src="~@/assets/img/sign/github.png"
+            srcset="~@/assets/img/sign/github@2x.png"
+            alt="github"
+          />
+          <el-form-item label="Github" prop="github">
+            <el-input placeholder="请输入需绑定账号用户名" v-model="social.github"></el-input>
+          </el-form-item>
+          <span class="opts">
+            <el-button type="info" @click="handleCancel('github')">取消</el-button>
+            <el-button type="primary" @click="onSubmit('github')">确认</el-button>
+          </span>
+        </div>
+        <div class="line">
+          <img
+            class="prefix-icon"
+            src="~@/assets/img/sign/zhihu.png"
+            srcset="~@/assets/img/sign/zhihu@2x.png"
+            alt="zhihu"
+          />
+          <el-form-item label="知乎" prop="zhihu">
+            <el-input placeholder="请输入需绑定账号用户名" v-model="social.zhihu"></el-input>
+          </el-form-item>
+          <span class="opts">
+            <el-button type="info" @click="handleCancel('zhihu')">取消</el-button>
+            <el-button type="primary" @click="onSubmit('zhihu')">确认</el-button>
+          </span>
+        </div>
+        <div class="line">
+          <img
+            class="prefix-icon"
+            src="~@/assets/img/sign/stackoverflow.png"
+            srcset="~@/assets/img/sign/stackoverflow@2x.png"
+            alt="stackoverflow"
+          />
+          <el-form-item label="StackOverflow" prop="stackoverflow">
+            <el-input placeholder="请输入需绑定账号用户名" v-model="social.stackoverflow"></el-input>
+          </el-form-item>
+          <span class="opts">
+            <el-button type="info" @click="handleCancel('stackoverflow')">取消</el-button>
+            <el-button type="primary" @click="onSubmit('stackoverflow')">确认</el-button>
+          </span>
+        </div>
+        <div class="line">
+          <img
+            class="prefix-icon"
+            src="~@/assets/img/sign/dribbble.png"
+            srcset="~@/assets/img/sign/dribbble@2x.png"
+            alt="dribbble"
+          />
+          <el-form-item label="Dribbble" prop="dribbble">
+            <el-input placeholder="请输入需绑定账号用户名" v-model="social.dribbble"></el-input>
+          </el-form-item>
+          <span class="opts">
+            <el-button type="info" @click="handleCancel('dribbble')">取消</el-button>
+            <el-button type="primary" @click="onSubmit('dribbble')">确认</el-button>
+          </span>
+        </div>
+      </el-form>
+    </div>
+  </div>
 </template>
 
 <script>
+import uploader from "@/components/uploader";
 export default {
-}
+  data() {
+    return {
+      // editing: true,
+      editingItem: [],
+      rules: {
+        name: ""
+      },
+      social: {
+        imageUrl: "",
+        start: "",
+        end: "",
+        company: "",
+        position: "",
+        des: ""
+      },
+      experience: [
+        {
+          imageUrl: "",
+          start: "2019-01-02",
+          end: "2019-01-02",
+          company: "程序员客栈",
+          position: "高级产品经理",
+          des:
+            "主要负责程序员客栈“雇佣直通车、1980服务、云端项目、雇佣项目“项目前后端开发,参与整个项目的设计、需求讨论、代码开发、联调测试及系统维护迭代。 【主要工作成就】:解决“雇佣直通车”项目,系统智能自动匹配算法问题。"
+        }
+      ],
+      current: null
+    };
+  },
+  components: {
+    uploader
+  },
+  methods: {
+    onSubmit(idx) {
+      console.log("submit!", this.form);
+      this.experience.push(this.form);
+    },
+    handleAdd() {
+      this.experience.push(this.init);
+      this.editingItem.push(this.experience.length - 1);
+    },
+    handleImageUrl(url) {
+      this.form.imageUrl = url;
+    },
+    handleDelete(idx) {
+      this.experience.splice(this.experience.indexOf(this.current), 1);
+    },
+    handleCancel(idx) {
+      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+    },
+    editItem(idx) {
+      this.editingItem.push(idx);
+    }
+  }
+};
 </script>
 
-<style>
+<style lang="scss">
+.info {
+  header .el-icon-plus {
+    font-size: 18px;
+  }
+  .edit {
+    padding: 20px;
+    > form {
+      .opts {
+        float: right;
+      }
+      .to {
+        margin-right: 10px;
+      }
+      .line {
+        position: relative;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        height: 80px;
+        border-bottom: 1px solid #ebeef5;
+        .el-form-item {
+          margin-bottom: 0;
+        }
+        .el-input {
+          width: 586px;
+        }
+        .prefix-icon {
+          position: absolute;
+          left: 0;
+          top: 50%;
+          transform: translateY(-50%);
+          width: 26px;
+          height: 26px;
+          z-index: 10;
+        }
+      }
+      .el-form-item__label {
+        text-align: left;
+        padding-left: 30px;
+      }
+    }
+  }
+}
 </style>

+ 226 - 3
components/sign/works.vue

@@ -1,11 +1,234 @@
 <template>
-  <div>目前SSR未有页面</div>
+  <div class="works">
+    <header>
+      <h5>作品</h5>
+      <span>
+        <el-button @click="handleAdd" type="text" icon="el-icon-plus"></el-button>
+      </span>
+    </header>
+    <div v-if="works.length > 0">
+      <template v-for="(item, idx) in works">
+        <div v-if="editingItem.indexOf(idx) < 0" :key="item.company" class="show">
+          <span class="star">
+            <img src="~@/assets/img/sign/star.png" srcset="~@/assets/img/sign/star@2x.png" alt />
+          </span>
+          <span class="image" v-if="works[idx].images[0]">
+            <img :src="works[idx].images[0].url" alt />
+          </span>
+          <span class="des">
+            <h4>
+              <span>{{`${item.start} - ${item.end} ${item.company} ${item.position}`}}</span>
+              <el-button @click="editItem(idx)" type="text">修改</el-button>
+            </h4>
+            <p>{{item.des}}</p>
+          </span>
+        </div>
+        <div v-else :key="item.name" class="edit">
+          <el-form ref="form" :rules="rules" :model="works[idx]" label-width="147px">
+            <el-form-item label="作品名称" prop="name">
+              <el-input
+                :style="{width: '440px'}"
+                v-model="works[idx].name"
+                placeholder="50字以内 不能包含 & ¥ % / \ *"
+              ></el-input>
+              <span class="opts">
+                <el-button type="info" @click="handleCancel(idx)">取消</el-button>
+                <el-button type="primary" @click="onSubmit(idx)">确认</el-button>
+                <el-button type="text" icon="el-icon-delete" @click="handleDelete(idx)"></el-button>
+              </span>
+            </el-form-item>
+            <div class="inline">
+              <el-form-item label="行业类型" prop="industry">
+                <el-select
+                  :style="{width: '217px'}"
+                  v-model="works[idx].industry"
+                  placeholder="选择行业类型"
+                >
+                  <el-option v-for="item in 5" :label="`${item}分`" :key="item" value="item"></el-option>
+                </el-select>
+              </el-form-item>
+              <el-form-item label="关键功能" prop="key">
+                <el-select :style="{width: '217px'}" v-model="works[idx].key" placeholder="请选择">
+                  <el-option v-for="item in 5" :label="`${item}分`" :key="item" value="item"></el-option>
+                </el-select>
+              </el-form-item>
+            </div>
+            <el-form-item label="行业类型" prop="type">
+              <el-input type="textarea" :rows="5" placeholder="请输入" v-model="works[idx].type"></el-input>
+            </el-form-item>
+            <el-form-item label="作品职责" prop="des">
+              <el-input
+                type="textarea"
+                :rows="4"
+                placeholder="描述你在该作品中承担的责任,完成了哪些工作(不少于15字符)"
+                v-model="works[idx].des"
+              ></el-input>
+            </el-form-item>
+            <el-form-item label="作品名称" prop="url">
+              <el-input
+                placeholder="例如:https://www.proginn.com 若无法添加作品有效链接,请添加作品截图"
+                v-model="works[idx].des"
+              ></el-input>
+            </el-form-item>
+            <el-form-item label="作品截图" prop="images">
+              <multi-uploader v-model="works[idx].images"></multi-uploader>
+            </el-form-item>
+          </el-form>
+        </div>
+      </template>
+    </div>
+    <div v-else class="empty">点击右上角“添加”按钮添加作品(至少添加3项)</div>
+  </div>
 </template>
 
 <script>
+import multiUploader from "@/components/multi-uploader";
 export default {
-}
+  data() {
+    return {
+      // editing: true,
+      editingItem: [0],
+      rules: {
+        name: ""
+      },
+      init: {
+        name: "",
+        industry: "",
+        key: "",
+        type: "",
+        des: "",
+        url: "",
+        images: []
+      },
+      works: [
+        {
+          name: "网易云音乐产品设计",
+          industry: "娱乐",
+          key: "Javascript",
+          type: "音乐",
+          des:
+            "主要负责程序员客栈“雇佣直通车、1980服务、云端项目、雇佣项目“项目前后端开发,参与整个项目的设计、需求讨论、代码开发、联调测试及系统维护迭代。 【主要工作成就】:解决“雇佣直通车”项目,系统智能自动匹配算法问题。解决“雇佣直通车”项目,系统智能自动匹配算法问题。",
+          url: "https://picsum.photos/102/102",
+          images: [
+            {
+              name: "mock pic",
+              url: "https://picsum.photos/102/102"
+            }
+          ]
+        }
+      ],
+      current: null
+    };
+  },
+  components: {
+    multiUploader
+  },
+  methods: {
+    onSubmit(idx) {
+      console.log("submit!", this.form);
+      this.works.push(this.form);
+    },
+    handleAdd() {
+      this.works.push(this.init);
+      this.editingItem.push(this.works.length - 1);
+    },
+    handleImageUrl(url) {
+      this.form.imageUrl = url;
+    },
+    handleDelete(idx) {
+      this.works.splice(this.works.indexOf(this.current), 1);
+    },
+    handleCancel(idx) {
+      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+    },
+    editItem(idx) {
+      this.editingItem.push(idx);
+    }
+  }
+};
 </script>
 
-<style>
+<style lang="scss" scoped>
+.works {
+  header .el-icon-plus {
+    font-size: 18px;
+  }
+  .edit {
+    padding: 20px;
+    > form {
+      .opts {
+        float: right;
+      }
+      .inline {
+        display: flex;
+      }
+      .to {
+        margin-right: 10px;
+      }
+      .times {
+        .el-checkbox {
+          width: 88px;
+        }
+        .el-input {
+          width: 136px;
+        }
+      }
+      .content {
+        display: flex;
+        justify-content: space-between;
+        align-items: flex-start;
+        margin-top: 10px;
+        .el-textarea {
+          display: flex;
+          width: 766px;
+          height: 162px;
+        }
+      }
+    }
+  }
+  .show {
+    padding: 23px 33px 23px 20px;
+    border-bottom: 1px solid #ebeef5;
+    &:last-of-type {
+      border: 0;
+    }
+    h4 {
+      display: flex;
+      justify-content: space-between;
+      height: 44px;
+      font-size: 14px;
+      font-family: PingFangSC-Medium;
+      font-weight: 500;
+      color: #308eff;
+      line-height: 44px;
+    }
+    p {
+      margin-top: 8px;
+      font-size: 14px;
+      font-family: PingFangSC-Regular;
+      font-weight: 400;
+      color: rgba(102, 102, 102, 1);
+      line-height: 24px;
+    }
+  }
+
+  .empty {
+    margin: 112px auto 104px;
+    font-size: 27px;
+    font-family: PingFangSC-Regular;
+    font-weight: 400;
+    text-align: center;
+    color: rgba(205, 205, 205, 1);
+    line-height: 38px;
+  }
+  footer p {
+    margin-top: 15px;
+    width: 766px;
+    font-size: 12px;
+    font-family: PingFangSC-Regular;
+    font-weight: 400;
+    color: rgba(145, 154, 167, 1);
+    line-height: 17px;
+  }
+}
 </style>