Explorar el Código

fix: bugs of sign

ArvinQi hace 6 años
padre
commit
6745cff0f4

+ 119 - 0
components/date.vue

@@ -0,0 +1,119 @@
+<template>
+  <div class="uploader">
+    <el-upload
+      class="avatar-uploader"
+      action="#"
+      :show-file-list="false"
+      :multiple="false"
+      accept="image/png, image/jpeg"
+      :before-upload="handleFileChange"
+    >
+      <i v-if="imageUrl" class="el-icon-delete avatar-uploader-icon" @click.stop="handleDeleteFile"></i>
+      <img v-if="imageUrl" :src="imageUrl" class="avatar" />
+      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+      <span v-if="title" class="title">{{title}}</span>
+    </el-upload>
+  </div>
+</template>
+
+<script>
+export default {
+  props: ["imageUrl", "title"],
+  components: {},
+  data() {
+    return {
+      uploading: false
+    };
+  },
+  computed: {},
+  mounted() {},
+  methods: {
+    handleDeleteFile() {
+      this.$emit("change", "");
+    },
+    handleFileChange(file) {
+      // const file = e.target.files[0];
+      // if (file.size / 1024 > 500) {
+      //   this.$message.error("图片大小不得超过500k,请重新选择");
+      //   return false;
+      // }
+      const formData = new FormData();
+      formData.append("file", file);
+      formData.append("original_filename", file.name);
+      this.uploading = true;
+      this.$axios
+        .$post(`/upload_image`, formData, {
+          headers: { "Content-Type": "multipart/form-data" }
+        })
+        .then(res => {
+          this.$emit("change", res.filename);
+        })
+        .finally(() => {
+          this.uploading = false;
+        });
+    }
+  }
+};
+</script>
+
+<style lang="scss">
+.uploader {
+  position: relative;
+  background: #fff;
+  .el-icon-delete {
+    display: none;
+  }
+  .avatar-uploader .el-upload {
+    width: 184px;
+    height: 162px;
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+    img {
+      width: 100%;
+      height: auto;
+      object-fit: contain;
+      object-position: top left;
+    }
+  }
+  .avatar-uploader .el-upload:hover {
+    border-color: #409eff;
+    .el-icon-delete {
+      display: block;
+    }
+  }
+  .avatar-uploader-icon {
+    position: absolute;
+    top: 0;
+    left: 0;
+    font-size: 44px;
+    color: #dce1e8;
+    width: 184px;
+    height: 162px;
+    line-height: 160px;
+    text-align: center;
+    /* background: rgba(1, 1, 1, 0.1); */
+    :hover {
+      color: #409eff;
+    }
+  }
+  .avatar {
+    width: 184px;
+    height: 162px;
+    display: block;
+  }
+  .title {
+    position: absolute;
+    left: 50%;
+    bottom: 8px;
+    transform: translateX(-50%);
+    font-size: 13px;
+    font-family: PingFangSC-Medium;
+    font-weight: 500;
+    color: rgba(25, 34, 46, 1);
+    line-height: 18px;
+  }
+}
+</style>

+ 1 - 1
components/editor.vue

@@ -94,7 +94,7 @@ export default {
   },
   methods: {
     handleChange(e) {
-      if (!e.html) {
+      if (typeof e.html === "undefined") {
         return;
       }
       this.$emit("change", e.html);

+ 2 - 0
components/multi-uploader.vue

@@ -3,6 +3,7 @@
     <el-upload
       action="/upload_image"
       list-type="picture-card"
+      :limit="9"
       :file-list="fileList"
       :on-preview="handlePictureCardPreview"
       :on-remove="handleRemove"
@@ -13,6 +14,7 @@
     <el-dialog :visible.sync="dialogVisible">
       <img width="100%" :src="dialogImageUrl" alt />
     </el-dialog>
+    <div slot="tip" class="el-upload__tip">最多添加9张作品图片</div>
   </div>
 </template>
 

+ 26 - 6
components/sign/education.vue

@@ -3,7 +3,12 @@
     <header>
       <h5>教育经历</h5>
       <span>
-        <el-button @click="handleAdd" type="text" icon="el-icon-plus"></el-button>
+        <el-button
+          v-if="this.userinfo && this.userinfo.realname_verify_status !== '0'"
+          @click="handleAdd"
+          type="text"
+          icon="el-icon-plus"
+        ></el-button>
       </span>
     </header>
     <div v-if="education.length > 0">
@@ -109,6 +114,7 @@
 
 <script>
 import uploader from "@/components/uploader";
+import { mapState } from "vuex";
 export default {
   data() {
     return {
@@ -151,7 +157,9 @@ export default {
   components: {
     uploader
   },
-  computed: {},
+  computed: {
+    ...mapState(["userinfo"])
+  },
   watch: {},
   async mounted() {
     this.getData();
@@ -236,8 +244,15 @@ export default {
       this.rankDialog = false;
     },
     handleAdd() {
+      if (
+        this.editingItem.length > 0 &&
+        !this.education[this.editingItem[0]].id
+      ) {
+        this.$message.error("请先保存现有修改");
+        return;
+      }
       this.education.push(this.init);
-      this.editingItem.push(this.education.length - 1);
+      this.editingItem = [this.education.length - 1];
     },
     handleImageUrl(idx, url) {
       this.education[idx].diploma_photo = url;
@@ -245,12 +260,13 @@ export default {
     async handleDelete(idx) {
       const res = await this.onSubmit();
       if (res) {
+        this.editingItem = [];
         this.education.splice(idx, 1);
         this.originEducation.splice(idx, 1);
       }
     },
     handleCancel(idx, item) {
-      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+      this.editingItem = [];
       if (!item.id) {
         this.education.splice(idx, 1);
       }
@@ -274,7 +290,7 @@ export default {
         this.$message.error("请提供学历证明!");
         return;
       }
-      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+      this.editingItem = [];
       const submitItem = {
         ...item,
         start_time: item.date[0],
@@ -284,7 +300,11 @@ export default {
       this.onSubmit();
     },
     editItem(idx) {
-      this.editingItem.push(idx);
+      if (this.userinfo && this.userinfo.realname_verify_status === "0") {
+        this.$message.error("请先进行实名认证");
+        return;
+      }
+      this.editingItem = [idx];
     }
   }
 };

+ 242 - 0
components/sign/experience-form.vue

@@ -0,0 +1,242 @@
+<template>
+  <div class="edit">
+    <el-form ref="form" :rules="rules" :model="item" label-width="147px">
+      <div class="header">
+        <el-date-picker
+          v-model="item.date"
+          type="daterange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd"
+        ></el-date-picker>
+        <el-select
+          v-model="item.company"
+          allow-create
+          filterable
+          remote
+          reserve-keyword
+          placeholder="请输入公司名称"
+          :remote-method="fetchCompany"
+          :loading="loadingCompany"
+        >
+          <el-option
+            v-for="item in companys"
+            :key="item.label"
+            :label="item.label"
+            :value="item.label"
+          ></el-option>
+        </el-select>
+        <el-select
+          v-model="item.title"
+          allow-create
+          filterable
+          remote
+          reserve-keyword
+          placeholder="请输入职位"
+          :remote-method="fetchTitle"
+          :loading="loadingTitle"
+        >
+          <el-option
+            v-for="item in titles"
+            :key="item.label"
+            :label="item.label"
+            :value="item.label"
+          ></el-option>
+        </el-select>
+        <span class="opts">
+          <el-button type="danger" @click="handleDelete(item, idx)">删除</el-button>
+          <el-button type="info" @click="handleCancel(item, idx)">取消</el-button>
+          <el-button type="primary" @click="handleConfirm(item, idx)">确认</el-button>
+        </span>
+      </div>
+      <div class="content">
+        <el-input
+          type="textarea"
+          :rows="7"
+          placeholder="请从主要工作内容、成就等方面,描述你的工作经历,字数不少于60字符"
+          v-model="item.description"
+        ></el-input>
+        <uploader
+          :imageUrl="item.work_certify_img"
+          title="工作证明"
+          @change="val => handleImageUrl(idx, val)"
+        ></uploader>
+      </div>
+      <footer>
+        <p>注:有效的工作证明包括:工牌/入职通知邮件/在职证明/公司邮箱截图/公司获奖证书/钉钉截图/离职证明/社保公积金证明等(其中之一即可,截图中需同时出现公司信息和个人信息,才能作为有效工作证明,并与目前公司相一致)</p>
+      </footer>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import uploader from "@/components/uploader";
+export default {
+  props: ["idx", "item", "handleDelete", "handleCancel", "handleConfirm"],
+  components: {
+    uploader
+  },
+  data() {
+    return {
+      rules: {
+        // date: [
+        //   {
+        //     required: true,
+        //     message: "请设置开始时间/结束时间",
+        //     trigger: "change"
+        //   }
+        // ],
+        // company: [
+        //   {
+        //     required: true,
+        //     message: "请设置公司名称/职位",
+        //     trigger: "change"
+        //   }
+        // ],
+        // title: [
+        //   {
+        //     required: true,
+        //     message: "请设置公司名称/职位",
+        //     trigger: "change"
+        //   }
+        // ],
+        // description: [
+        //   { min: 60, message: "经历描述不少于60字符", trigger: "blur" }
+        // ]
+        name: [
+          {
+            required: true,
+            message: "作品名称不得为空",
+            trigger: "blur"
+          },
+          { max: 50, message: "作品名称不得超过50字符", trigger: "blur" },
+          {
+            validator: (rule, value, callback) => {
+              if (/[&¥%\/\*]+/.test(value)) {
+                callback(new Error("作品名称不包含特殊字符"));
+              } else {
+                callback();
+              }
+            },
+            trigger: "blur"
+          }
+        ],
+        description: [
+          {
+            required: true,
+            message: "作品简介不得为空",
+            trigger: "blur"
+          },
+          { min: 60, message: "作品简介不得低于60字符", trigger: "blur" }
+        ],
+        industry_id: [
+          {
+            required: true,
+            message: "行业类型不得为空",
+            trigger: "change"
+          }
+        ],
+        function_ops: [
+          {
+            required: true,
+            message: "关键功能不得为空",
+            trigger: "change"
+          }
+        ],
+        duty: [
+          {
+            required: true,
+            message: "作品职责不得为空",
+            trigger: "blur"
+          },
+          { min: 15, message: "作品职责不得低于15字符", trigger: "blur" },
+          { max: 200, message: "作品职责不得高于200字符", trigger: "blur" }
+        ]
+      },
+      companys: [],
+      loadingCompany: false,
+      titles: [],
+      loadingTitle: false
+    };
+  },
+  computed: {},
+  async mounted() {},
+  methods: {
+    async handleSubmit(idx) {
+      this.$refs["form"].validate(async valid => {
+        if (valid) {
+          console.log("submit!", this.item);
+          const item = this.item;
+          this.onSubmit(this.item, idx);
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    async fetchCompany(keyword) {
+      this.loadingCompany = true;
+      const res = await this.$axios.$post("/api/simple_data/select_company", {
+        keyword
+      });
+      this.loadingCompany = false;
+      const data = res.data || [];
+      this.companys = data.map(it => ({ value: it.id, label: it.name }));
+    },
+    async fetchTitle(keyword) {
+      this.loadingTitle = true;
+      const res = await this.$axios.$post("/api/simple_data/select_title", {
+        keyword
+      });
+      this.loadingTitle = false;
+      const data = res.data || [];
+      this.titles = data.map(it => ({ value: it.id, label: it.name }));
+    },
+    handleImageUrl(idx, url) {
+      this.item.work_certify_img = url;
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.edit {
+  padding: 20px;
+  > form {
+    .opts {
+      display: flex;
+      align-items: center;
+      float: right;
+      .el-button {
+        margin-left: 5px;
+      }
+    }
+    .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;
+      }
+    }
+  }
+}
+</style>

+ 53 - 139
components/sign/experience.vue

@@ -8,13 +8,18 @@
           <el-form ref="form" :model="rankForm" class="first-form">
             <el-radio-group v-model="rankForm.first">
               <template v-for="(item, idx) in experience">
-                <el-radio v-if="item.isAuth == 1" :label="item.id" :value="item.id" :key="item.id">
+                <el-radio
+                  v-if="item.work_certify_img"
+                  :label="item.id"
+                  :value="item.id"
+                  :key="item.id"
+                >
                   <div class="first-radio">
                     <span class="des">
                       <span>{{item.company}}</span>
                       <span>{{item.title}}</span>
                     </span>
-                    <el-button @click="editItem(idx)" type="text">编辑</el-button>
+                    <el-button @click="editItem(item, idx)" type="text">编辑</el-button>
                   </div>
                 </el-radio>
               </template>
@@ -42,7 +47,12 @@
             <el-button type="primary" @click="handleRank">确 定</el-button>
           </span>
         </el-dialog>
-        <el-button @click="handleAdd" type="text" icon="el-icon-plus"></el-button>
+        <el-button
+          v-if="this.userinfo && this.userinfo.realname_verify_status !== '0'"
+          @click="handleAdd"
+          type="text"
+          icon="el-icon-plus"
+        ></el-button>
       </span>
     </header>
     <div v-if="experience.length > 0">
@@ -52,79 +62,19 @@
             <span>{{`${item.start_time} - ${item.end_time || '至今'} ${item.company} ${item.title}`}}</span>
             <span v-if="item.is_main == '1'" class="first">优先展示</span>
             <span v-if="item.isAuth == 1" class="verify">已认证</span>
-            <el-button @click="editItem(idx)" type="text">编辑</el-button>
+            <el-button @click="editItem(item, idx)" type="text">编辑</el-button>
           </h4>
           <p>{{item.description}}</p>
         </div>
-        <div v-else :key="'experience' + idx" class="edit">
-          <el-form ref="form" :rules="rules" :model="item" label-width="147px">
-            <div class="header">
-              <el-date-picker
-                v-model="item.date"
-                type="daterange"
-                range-separator="至"
-                start-placeholder="开始日期"
-                end-placeholder="结束日期"
-                value-format="yyyy-MM-dd"
-              ></el-date-picker>
-              <el-select
-                v-model="item.company"
-                allow-create
-                filterable
-                remote
-                reserve-keyword
-                placeholder="请输入公司名称"
-                :remote-method="fetchCompany"
-                :loading="loadingCompany"
-              >
-                <el-option
-                  v-for="item in companys"
-                  :key="item.label"
-                  :label="item.label"
-                  :value="item.label"
-                ></el-option>
-              </el-select>
-              <el-select
-                v-model="item.title"
-                allow-create
-                filterable
-                remote
-                reserve-keyword
-                placeholder="请输入职位"
-                :remote-method="fetchTitle"
-                :loading="loadingTitle"
-              >
-                <el-option
-                  v-for="item in titles"
-                  :key="item.label"
-                  :label="item.label"
-                  :value="item.label"
-                ></el-option>
-              </el-select>
-              <span class="opts">
-                <el-button type="danger" @click="handleDelete(idx, item)">删除</el-button>
-                <el-button type="info" @click="handleCancel(idx, item)">取消</el-button>
-                <el-button type="primary" @click="handleConfirm(idx, item)">确认</el-button>
-              </span>
-            </div>
-            <div class="content">
-              <el-input
-                type="textarea"
-                :rows="7"
-                placeholder="请从主要工作内容、成就等方面,描述你的工作经历,字数不少于60字符"
-                v-model="item.description"
-              ></el-input>
-              <uploader
-                :imageUrl="item.work_certify_img"
-                title="工作证明"
-                @change="val => handleImageUrl(idx, val)"
-              ></uploader>
-            </div>
-            <footer>
-              <p>注:有效的工作证明包括:工牌/入职通知邮件/在职证明/公司邮箱截图/公司获奖证书/钉钉截图/离职证明/社保公积金证明等(其中之一即可,截图中需同时出现公司信息和个人信息,才能作为有效工作证明,并与目前公司相一致)</p>
-            </footer>
-          </el-form>
-        </div>
+        <experience-form
+          v-else
+          :key="`experience${idx}`"
+          :idx="idx"
+          :item="item"
+          :handleCancel="handleCancel"
+          :handleConfirm="handleConfirm"
+          :handleDelete="handleDelete"
+        ></experience-form>
       </template>
     </div>
     <div v-else class="empty">点击右上角“添加”按钮添加工作经历</div>
@@ -132,38 +82,15 @@
 </template>
 
 <script>
-import uploader from "@/components/uploader";
+import { mapState } from "vuex";
+import experienceForm from "./experience-form";
+
 export default {
   data() {
     return {
       // editing: true,
       editingItem: [],
-      rules: {
-        // date: [
-        //   {
-        //     required: true,
-        //     message: "请设置开始时间/结束时间",
-        //     trigger: "change"
-        //   }
-        // ],
-        // company: [
-        //   {
-        //     required: true,
-        //     message: "请设置公司名称/职位",
-        //     trigger: "change"
-        //   }
-        // ],
-        // title: [
-        //   {
-        //     required: true,
-        //     message: "请设置公司名称/职位",
-        //     trigger: "change"
-        //   }
-        // ],
-        // description: [
-        //   { min: 60, message: "经历描述不少于60字符", trigger: "blur" }
-        // ]
-      },
+      rules: {},
       init: {
         work_certify_img: "",
         start_time: "",
@@ -190,23 +117,21 @@ export default {
       rankDialog: false,
       rankForm: {
         first: ""
-      },
-      companys: [],
-      loadingCompany: false,
-      titles: [],
-      loadingTitle: false
+      }
     };
   },
   components: {
-    uploader
+    experienceForm
+  },
+  computed: {
+    ...mapState(["userinfo"])
   },
-  computed: {},
   watch: {},
   async mounted() {
     this.getData();
   },
   methods: {
-    async onSubmit(idx) {
+    async onSubmit() {
       console.log("submit!", this.originExperience);
       if (this.originExperience.length > 10) {
         this.$message.error("最多可添加10项工作经历!");
@@ -229,24 +154,6 @@ export default {
       this.experience = experience;
       this.originExperience = data;
     },
-    async fetchCompany(keyword) {
-      this.loadingCompany = true;
-      const res = await this.$axios.$post("/api/simple_data/select_company", {
-        keyword
-      });
-      this.loadingCompany = false;
-      const data = res.data || [];
-      this.companys = data.map(it => ({ value: it.id, label: it.name }));
-    },
-    async fetchTitle(keyword) {
-      this.loadingTitle = true;
-      const res = await this.$axios.$post("/api/simple_data/select_title", {
-        keyword
-      });
-      this.loadingTitle = false;
-      const data = res.data || [];
-      this.titles = data.map(it => ({ value: it.id, label: it.name }));
-    },
     handleRankClose() {
       this.rankForm = {
         first: ""
@@ -266,26 +173,29 @@ export default {
       this.rankDialog = false;
     },
     handleAdd() {
+      if (
+        this.editingItem.length > 0 &&
+        !this.experience[this.editingItem[0]].id
+      ) {
+        this.$message.error("请先保存现有修改");
+        return;
+      }
       this.experience.push(this.init);
-      this.editingItem.push(this.experience.length - 1);
+      this.editingItem = [this.experience.length - 1];
     },
-    handleImageUrl(idx, url) {
-      this.experience[idx].work_certify_img = url;
-    },
-    handleDelete(idx) {
+    handleDelete(item, idx) {
       this.experience.splice(idx, 1);
       this.originExperience.splice(idx, 1);
-      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+      this.editingItem = [];
       this.onSubmit();
     },
-    handleCancel(idx, item) {
-      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+    handleCancel(item, idx) {
+      this.editingItem = [];
       if (!item.id) {
         this.experience.splice(idx, 1);
       }
     },
-    handleConfirm(idx) {
-      const item = this.experience.slice(idx, idx + 1)[0];
+    handleConfirm(item, idx) {
       const origin = this.originExperience.slice(idx, idx + 1)[0];
       if (item == origin) {
         this.$message.error("请修改后保存!");
@@ -303,7 +213,7 @@ export default {
         this.$message.error("经历描述不少于60字符!");
         return;
       }
-      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+      this.editingItem = [];
       const submitItem = {
         ...item,
         start_time: item.date[0],
@@ -312,9 +222,13 @@ export default {
       this.originExperience.splice(idx, 1, submitItem);
       this.onSubmit();
     },
-    editItem(idx) {
+    editItem(item, idx) {
+      if (this.userinfo && this.userinfo.realname_verify_status === "0") {
+        this.$message.error("请先进行实名认证");
+        return;
+      }
       this.rankDialog = false;
-      this.editingItem.push(idx);
+      this.editingItem = [idx];
     }
   }
 };

+ 196 - 94
components/sign/info.vue

@@ -9,10 +9,10 @@
     </header>
     <div class="edit">
       <el-form ref="form" :rules="rules" :model="form" label-width="147px">
-        <el-form-item label="昵称">
-          <el-input v-model="form.nickname" maxLength="50"></el-input>
+        <el-form-item label="昵称" prop="nickname">
+          <el-input v-model="form.nickname" maxlength="50"></el-input>
         </el-form-item>
-        <el-form-item label="工作状态">
+        <el-form-item label="工作状态" prop="type">
           <el-select v-model="form.type" placeholder="请选择">
             <el-option
               v-for="type in types"
@@ -22,7 +22,7 @@
             ></el-option>
           </el-select>
         </el-form-item>
-        <el-form-item label="职业方向">
+        <el-form-item label="职业方向" prop="direction_op">
           <el-select v-model="form.occupation_op" placeholder="请选择">
             <el-option
               v-for="item in directions"
@@ -40,14 +40,9 @@
             ></el-option>
           </el-select>
         </el-form-item>
-        <el-form-item label="所在地区">
+        <el-form-item label="所在地区" prop="city_op_id">
           <el-select v-model="form.province_op_id" placeholder="请选择" @change="getCities">
-            <el-option
-              v-for="item in provinces"
-              :key="item.id"
-              :label="item.name"
-              :value="item.id"
-            ></el-option>
+            <el-option v-for="item in provinces" :key="item.id" :label="item.name" :value="item.id"></el-option>
           </el-select>
           <!-- <el-date-picker
               type="date"
@@ -56,16 +51,11 @@
               style="width: 100%;"
           ></el-date-picker>-->
           <el-select v-model="form.city_op_id" placeholder="请选择">
-            <el-option
-              v-for="item in cities"
-              :key="item.id"
-              :label="item.name"
-              :value="item.id"
-            ></el-option>
+            <el-option v-for="item in cities" :key="item.id" :label="item.name" :value="item.id"></el-option>
           </el-select>
           <!-- <el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker> -->
         </el-form-item>
-        <el-form-item label="日薪">
+        <el-form-item label="日薪" prop="work_price">
           <el-input-number
             :min="300"
             :max="2000"
@@ -74,7 +64,7 @@
             :style="{width: '150px', marginRight: '10px'}"
           ></el-input-number>元/天(8小时)
         </el-form-item>
-        <el-form-item label="可工作时间">
+        <el-form-item label="可工作时间" prop="workday">
           <div class="times">
             <el-checkbox v-model="form.workday" label="工作日"></el-checkbox>
             <el-time-select
@@ -97,6 +87,8 @@
               placeholder="结束时间"
             ></el-time-select>
           </div>
+        </el-form-item>
+        <el-form-item prop="weekend">
           <div class="times">
             <el-checkbox v-model="form.weekend" label="周末"></el-checkbox>
             <el-time-select
@@ -126,6 +118,7 @@
 </template>
 
 <script>
+import { mapState } from "vuex";
 const types = [
   {
     value: "2",
@@ -144,9 +137,103 @@ export default {
   data() {
     return {
       rules: {
-        nickname: ""
+        nickname: [
+          {
+            required: true,
+            message: "请完善昵称信息",
+            trigger: "blur"
+          },
+          { max: 50, message: "昵称不得超过50字符", trigger: "blur" },
+          {
+            validator: (rule, value, callback) => {
+              console.log(this.regPhone);
+              if (this.regPhone.test(value)) {
+                callback(new Error("请不要使用手机号作为昵称"));
+              } else {
+                callback();
+              }
+            },
+            trigger: "blur"
+          },
+          {
+            validator: (rule, value, callback) => {
+              if (this.regSpecialChar.test(value)) {
+                callback(new Error("昵称不得使用特殊字符"));
+              } else {
+                callback();
+              }
+            },
+            trigger: "blur"
+          }
+        ],
+        type: [
+          {
+            required: true,
+            message: "请设置当前工作状态",
+            trigger: "blur"
+          }
+        ],
+        address: [
+          {
+            required: true,
+            message: "请设置所在地区信息",
+            trigger: "blur"
+          }
+        ],
+        work_price: [
+          {
+            required: true,
+            message: "请设置日薪",
+            trigger: "blur"
+          },
+          {
+            validator: (rule, value, callback) => {
+              if (value < 300 || value > 2000) {
+                callback(new Error("日薪只允许设置300--2000范围内的正整数"));
+              } else {
+                callback();
+              }
+            },
+            trigger: "blur"
+          }
+        ],
+        workday: [
+          {
+            validator: (rule, value, callback) => {
+              console.log(value);
+              if (!value && !this.form.weekend) {
+                callback(new Error("请完善可工作时间"));
+              } else if (
+                value &&
+                (!this.form.workdayStart || !this.form.workdayEnd)
+              ) {
+                callback(new Error("请完善工作日可工作时间"));
+              } else {
+                callback();
+              }
+            },
+            trigger: "change"
+          }
+        ],
+        weekend: [
+          {
+            validator: (rule, value, callback) => {
+              if (!value && !this.form.workday) {
+                callback(new Error("请完善可工作时间"));
+              } else if (
+                value &&
+                (!this.form.weekendStart || !this.form.weekendEnd)
+              ) {
+                callback(new Error("请完善周末可工作时间"));
+              } else {
+                callback();
+              }
+            },
+            trigger: "change"
+          }
+        ]
       },
-      userInfo:{},
+      userInfo: {},
       form: {
         nickname: "",
         type: "",
@@ -163,18 +250,19 @@ export default {
         weekendEnd: "",
         dailyRate: "",
         workdayTime: "",
-        province_op_id:'',
-        city_op_id:''
+        province_op_id: "",
+        city_op_id: ""
       },
       editing: false,
       types,
       directions: [],
       regions: [],
-      provinces:[],
-      cities:[]
+      provinces: [],
+      cities: []
     };
   },
   computed: {
+    ...mapState(["regPhone", "regSpecialChar"]),
     subDirections: function() {
       let direction = this.form.occupation_op;
       let current = null;
@@ -239,100 +327,114 @@ export default {
     this.form.occupation_op = this.userInfo.occupation_op;
     this.form.direction_op = this.userInfo.direction_op;
     this.form.work_price = this.userInfo.work_price;
-    this.form.province_op_id=this.userInfo.province_op_id;
-    this.form.city_op_id=this.userInfo.city_op_id;
+    this.form.province_op_id = this.userInfo.province_op_id;
+    this.form.city_op_id = this.userInfo.city_op_id;
     const work_time_op = this.userInfo.work_time_op;
-    if (work_time_op){
+    if (work_time_op) {
       if (work_time_op.weekend) {
-        this.form.weekend=true;
+        this.form.weekend = true;
         this.form.weekendStart = work_time_op.weekend[0];
         this.form.weekendEnd = work_time_op.weekend[1];
-      }else{
-        this.form.weekend=false;
+      } else {
+        this.form.weekend = false;
       }
-      if (work_time_op.workday){
-        this.form.workday=true;
+      if (work_time_op.workday) {
+        this.form.workday = true;
         this.form.workdayStart = work_time_op.workday[0];
         this.form.workdayEnd = work_time_op.workday[1];
-      }else{
-        this.form.workday=false;
+      } else {
+        this.form.workday = false;
       }
     }
 
     this.getDirection();
     this.getProvinces();
-    this.form.province_op_id=this.form.province_op_id?this.form.province_op_id:10;
-    this.getCities(this.form.province_op_id);
+    this.form.province_op_id = this.form.province_op_id
+      ? this.form.province_op_id
+      : 10;
+    this.getCities(this.form.province_op_id, true);
   },
   methods: {
     async onSubmit() {
       //console.log("submit!");
-      const form = this.form;
-      const work_time_op = {};
-      if (form.weekend) {
-        work_time_op.weekend = [form.weekendStart, form.weekendEnd];
-      }
-      if (form.workday) {
-        work_time_op.workday = [form.workdayStart, form.workdayEnd];
-      }
-      const data = {
-        work_time_op: JSON.stringify(work_time_op),
-        province_op_id: this.form.province_op_id,
-        city_op_id: this.form.city_op_id,
-        // district_op_name: '',
-        // work_time_per_work: '',
-        // work_remote: '',
-        // work_area: '',
-        // province_op: '', // 远程工作
-        work_price: form.work_price,
-        nickname: form.nickname,
-        type: form.type,
-        occupation_op: form.occupation_op,
-        direction_op: form.direction_op
-      };
-      const res = await this.$axios.$post("/api/user/update_info", data);
-      if (res.status === 1) {
-        this.$message.success("保存成功!");
-        this.editing = false;
-      } else {
-        this.$message.error(res.info);
-      }
+      this.$refs["form"].validate(async valid => {
+        if (!valid) {
+          this.$message.error("填写有误");
+          return false;
+        }
+        const form = this.form;
+        const work_time_op = {};
+        if (form.weekend) {
+          work_time_op.weekend = [form.weekendStart, form.weekendEnd];
+        }
+        if (form.workday) {
+          work_time_op.workday = [form.workdayStart, form.workdayEnd];
+        }
+        const data = {
+          work_time_op: JSON.stringify(work_time_op),
+          province_op_id: this.form.province_op_id,
+          city_op_id: this.form.city_op_id,
+          // district_op_name: '',
+          // work_time_per_work: '',
+          // work_remote: '',
+          // work_area: '',
+          // province_op: '', // 远程工作
+          work_price: form.work_price,
+          nickname: form.nickname,
+          type: form.type,
+          occupation_op: form.occupation_op,
+          direction_op: form.direction_op
+        };
+        const res = await this.$axios.$post("/api/user/update_info", data);
+        if (res.status === 1) {
+          this.$message.success("保存成功!");
+          this.editing = false;
+        } else {
+          this.$message.error(res.info);
+        }
+      });
     },
     async getDirection() {
       const res = await this.$axios.$post("/api/direction/get_all_data");
       this.directions = res.data || [];
     },
-    async getProvinces(){
+    async getProvinces() {
       const res = await this.$axios.$post("/api/geo/get_province_list");
       this.provinces = res.data || [];
     },
-    async getCities(id){
-      const res=await this.$axios.$post('/api/geo/get_city_list_by_province',{'prov_id':id});
-      this.cities=res.data || [];
-      this.form.city_op=res.data[0].id;
+    async getCities(id, flag) {
+      if (!flag) {
+        this.form.city_op_id = "";
+      }
+      const res = await this.$axios.$post(
+        "/api/geo/get_city_list_by_province",
+        { prov_id: id }
+      );
+      this.cities = res.data || [];
+      this.form.city_op = res.data[0].id;
     },
-    async onCancel(){
-        console.log(this.userInfo);
-        this.form.nickname = this.userInfo.nickname;
-        this.form.type = this.userInfo.type;
-        this.form.occupation_op = this.userInfo.occupation_op;
-        this.form.direction_op = this.userInfo.direction_op;
-        this.form.work_price = this.userInfo.work_price;
-        let work_time_op = this.userInfo.work_time_op;
-        if (work_time_op.weekend) {
-            this.form.weekend=true;
-            this.form.weekendStart = work_time_op.weekend[0];
-            this.form.weekendEnd = work_time_op.weekend[1];
-        }else{
-          this.form.weekend=false;
-        }
-        if (work_time_op.workday){
-          this.form.workday=true;
-          this.form.workdayStart = work_time_op.workday[0];
-          this.form.workdayEnd = work_time_op.workday[1];
-        }else{
-          this.form.workday=false;
-        }
+    async onCancel() {
+      console.log(this.userInfo);
+      this.form.nickname = this.userInfo.nickname;
+      this.form.type = this.userInfo.type;
+      this.form.occupation_op = this.userInfo.occupation_op;
+      this.form.direction_op = this.userInfo.direction_op;
+      this.form.work_price = this.userInfo.work_price;
+      let work_time_op = this.userInfo.work_time_op;
+      if (work_time_op.weekend) {
+        this.form.weekend = true;
+        this.form.weekendStart = work_time_op.weekend[0];
+        this.form.weekendEnd = work_time_op.weekend[1];
+      } else {
+        this.form.weekend = false;
+      }
+      if (work_time_op.workday) {
+        this.form.workday = true;
+        this.form.workdayStart = work_time_op.workday[0];
+        this.form.workdayEnd = work_time_op.workday[1];
+      } else {
+        this.form.workday = false;
+      }
     }
   }
 };

+ 28 - 1
components/sign/profile.vue

@@ -7,7 +7,11 @@
         <el-button type="primary" @click="onSubmit">确认</el-button>
       </div>
       <div v-else class="opts">
-        <el-button type="primary" @click="editing = true">编辑</el-button>
+        <el-button
+          v-if="this.userinfo && this.userinfo.realname_verify_status !== '0'"
+          type="primary"
+          @click="handleEdit"
+        >编辑</el-button>
       </div>
     </header>
     <div v-if="editing" class="edit">
@@ -18,6 +22,7 @@
 </template>
 
 <script>
+import { mapState } from "vuex";
 import editor from "@/components/editor";
 export default {
   data() {
@@ -32,15 +37,37 @@ export default {
     //   console.log(val);
     // }
   },
+  computed: {
+    ...mapState(["userinfo"])
+  },
   async mounted() {
     let res = await this.$axios.$post("/api/user/get_resume");
     this.content = res.data.personaldetails;
   },
   methods: {
+    handleEdit() {
+      if (this.userinfo && this.userinfo.realname_verify_status === "0") {
+        this.$message.error("请先进行实名认证");
+        return;
+      }
+      this.editing = true;
+    },
     handleChange(val) {
       this.content = val;
     },
     async onSubmit() {
+      if (!this.content) {
+        this.$message.error("请输入个人介绍");
+        return false;
+      }
+      if (this.content.length < 150) {
+        this.$message.error("个人介绍不得低于150字");
+        return false;
+      }
+      if (!this.content.length > 3000) {
+        this.$message.error("个人介绍不得 超过3000字");
+        return false;
+      }
       const formData = {
         personaldetails: this.content
       };

+ 10 - 7
components/sign/skills.vue

@@ -10,7 +10,7 @@
       <template v-for="(item, idx) in skills">
         <div v-if="editingItem.indexOf(idx) < 0" :key="item.skill_name" class="show">
           <h4>
-            <span>{{`技能名称: ${item.skill_name} 经验自评:${item.skill_level}分 1分为新入门,5分为满分`}}</span>
+            <span>{{`技能名称: ${item.skill_name} 经验自评:${item.skill_level}分 `}}</span>
             <el-button @click="editItem(idx)" type="text">编辑</el-button>
           </h4>
         </div>
@@ -120,7 +120,7 @@ export default {
       const res = await this.$axios.$post("/api/user_skills/save", data);
       if (res.status === 1) {
         this.$message.success(res.info);
-        this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+        this.editingItem = [];
         this.originSkills.splice(idx, 1, item);
       } else {
         // this.$message.error(res.info);
@@ -136,18 +136,21 @@ export default {
       this.skillList = data.map(it => ({ id: it.id, name: it.name }));
     },
     handleAdd() {
+      if (this.editingItem.length > 0 && !this.skills[this.editingItem[0]].id) {
+        this.$message.error("请先保存现有修改");
+        return;
+      }
       this.skills.push(this.init);
-      this.editingItem.push(this.skills.length - 1);
+      this.editingItem = [this.skills.length - 1];
     },
     async handleDelete(item, idx) {
-      console.log(item);
       const deleteComplete = () => {
         this.$message({
           type: "success",
           message: "删除成功!"
         });
         this.skills.splice(idx, 1);
-        this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+        this.editingItem = [];
       };
       this.$confirm("确认删除该技能?", "提示", {
         confirmButtonText: "确定",
@@ -176,14 +179,14 @@ export default {
         });
     },
     handleCancel(item, idx) {
-      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+      this.editingItem = [];
       if (!item.skill_id) {
         this.skills.splice(idx, 1);
       }
     },
     editItem(idx) {
       console.log("editItem:" + idx);
-      this.editingItem.push(idx);
+      this.editingItem = [idx];
     }
   }
 };

+ 0 - 17
components/sign/work-form.vue

@@ -155,23 +155,6 @@ export default {
         if (valid) {
           console.log("submit!", this.work);
           const work = this.work;
-
-          if (work.description.length < 60) {
-            this.$message.error("");
-            return;
-          }
-          if (work.description.length > 200) {
-            this.$message.error("");
-            return;
-          }
-          if (work.duty.length < 15) {
-            this.$message.error("");
-            return;
-          }
-          if (work.duty.length > 200) {
-            this.$message.error("");
-            return;
-          }
           this.onSubmit(this.work, idx);
         } else {
           console.log("error submit!!");

+ 9 - 5
components/sign/works.vue

@@ -91,7 +91,7 @@ export default {
       const res = await this.$axios.$post(`/api/user_works/save`, queryParams);
       if (res.status === 1) {
         this.$message.success(res.info);
-        this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+        this.editingItem = [];
         this.getData();
       }
     },
@@ -151,8 +151,12 @@ export default {
       // this.skillList = data.map(it => ({ value: it.id, label: it.name }));
     },
     handleAdd() {
+      if (this.editingItem.length > 0 && !this.works[this.editingItem[0]].id) {
+        this.$message.error("请先保存现有修改");
+        return;
+      }
       this.works.push(this.init);
-      this.editingItem.push(this.works.length - 1);
+      this.editingItem = [this.works.length - 1];
     },
     async handleDelete(work, idx) {
       const deleteComplete = () => {
@@ -161,7 +165,7 @@ export default {
           message: "删除成功!"
         });
         this.works.splice(idx, 1);
-        this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+        this.editingItem = [];
       };
       this.$confirm("确认删除该作品?", "提示", {
         confirmButtonText: "确定",
@@ -191,13 +195,13 @@ export default {
         });
     },
     handleCancel(work, idx) {
-      this.editingItem.splice(this.editingItem.indexOf(idx), 1);
+      this.editingItem = [];
       if (!work.wid) {
         this.works.splice(idx, 1);
       }
     },
     editItem(idx) {
-      this.editingItem.push(idx);
+      this.editingItem = [idx];
     }
   }
 };

+ 4 - 1
store/index.js

@@ -8,6 +8,9 @@ const store = () => new Vuex.Store({
     isWeixin: false,
     userinfo: {},
     wxConfig: {},
+    regPhone: /^(0|86|17951)?(13[0-9]|15[012356789]|166|17[35678]|18[0-9]|14[57])[0-9]{8}$/,
+    regEmail: /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/,
+    regSpecialChar: /[&¥%\/\*]+/
   },
   getters: {
     isLogin(state) {
@@ -33,4 +36,4 @@ const store = () => new Vuex.Store({
   }
 })
 
-export default store
+export default store