Browse Source

个人中心和裁剪头像

fengshaolong 2 years ago
parent
commit
7152da366e

+ 97 - 0
package-lock.json

@@ -11,6 +11,7 @@
         "core-js": "^3.8.3",
         "element-ui": "^2.15.8",
         "vue": "^2.6.14",
+        "vue-cropper": "^0.5.8",
         "vue-router": "^3.5.1",
         "vuex": "^3.6.2"
       },
@@ -19,6 +20,8 @@
         "@vue/cli-plugin-router": "~5.0.0",
         "@vue/cli-plugin-vuex": "~5.0.0",
         "@vue/cli-service": "~5.0.0",
+        "sass": "^1.54.4",
+        "sass-loader": "^13.0.2",
         "vue-template-compiler": "^2.6.14"
       }
     },
@@ -5514,6 +5517,12 @@
         "node": ">= 4"
       }
     },
+    "node_modules/immutable": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmmirror.com/immutable/-/immutable-4.1.0.tgz",
+      "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==",
+      "dev": true
+    },
     "node_modules/import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -8020,6 +8029,57 @@
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
       "dev": true
     },
+    "node_modules/sass": {
+      "version": "1.54.4",
+      "resolved": "https://registry.npmmirror.com/sass/-/sass-1.54.4.tgz",
+      "integrity": "sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==",
+      "dev": true,
+      "dependencies": {
+        "chokidar": ">=3.0.0 <4.0.0",
+        "immutable": "^4.0.0",
+        "source-map-js": ">=0.6.2 <2.0.0"
+      },
+      "bin": {
+        "sass": "sass.js"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/sass-loader": {
+      "version": "13.0.2",
+      "resolved": "https://registry.npmmirror.com/sass-loader/-/sass-loader-13.0.2.tgz",
+      "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==",
+      "dev": true,
+      "dependencies": {
+        "klona": "^2.0.4",
+        "neo-async": "^2.6.2"
+      },
+      "engines": {
+        "node": ">= 14.15.0"
+      },
+      "peerDependencies": {
+        "fibers": ">= 3.1.0",
+        "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0",
+        "sass": "^1.3.0",
+        "sass-embedded": "*",
+        "webpack": "^5.0.0"
+      },
+      "peerDependenciesMeta": {
+        "fibers": {
+          "optional": true
+        },
+        "node-sass": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/schema-utils": {
       "version": "2.7.1",
       "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-2.7.1.tgz",
@@ -8931,6 +8991,11 @@
         "csstype": "^3.1.0"
       }
     },
+    "node_modules/vue-cropper": {
+      "version": "0.5.8",
+      "resolved": "https://registry.npmmirror.com/vue-cropper/-/vue-cropper-0.5.8.tgz",
+      "integrity": "sha512-Xgi/aLQCcNCiBTUdovy/i4LWx0G7fQnAENBpDWA3J4i87Zlk9DJRksXrClsQ6nnaFRfQVkMimij5GEvAMaXdYw=="
+    },
     "node_modules/vue-hot-reload-api": {
       "version": "2.3.4",
       "resolved": "https://registry.npmmirror.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
@@ -13969,6 +14034,12 @@
       "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
       "dev": true
     },
+    "immutable": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmmirror.com/immutable/-/immutable-4.1.0.tgz",
+      "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==",
+      "dev": true
+    },
     "import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -15888,6 +15959,27 @@
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
       "dev": true
     },
+    "sass": {
+      "version": "1.54.4",
+      "resolved": "https://registry.npmmirror.com/sass/-/sass-1.54.4.tgz",
+      "integrity": "sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==",
+      "dev": true,
+      "requires": {
+        "chokidar": ">=3.0.0 <4.0.0",
+        "immutable": "^4.0.0",
+        "source-map-js": ">=0.6.2 <2.0.0"
+      }
+    },
+    "sass-loader": {
+      "version": "13.0.2",
+      "resolved": "https://registry.npmmirror.com/sass-loader/-/sass-loader-13.0.2.tgz",
+      "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==",
+      "dev": true,
+      "requires": {
+        "klona": "^2.0.4",
+        "neo-async": "^2.6.2"
+      }
+    },
     "schema-utils": {
       "version": "2.7.1",
       "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-2.7.1.tgz",
@@ -16626,6 +16718,11 @@
         "csstype": "^3.1.0"
       }
     },
+    "vue-cropper": {
+      "version": "0.5.8",
+      "resolved": "https://registry.npmmirror.com/vue-cropper/-/vue-cropper-0.5.8.tgz",
+      "integrity": "sha512-Xgi/aLQCcNCiBTUdovy/i4LWx0G7fQnAENBpDWA3J4i87Zlk9DJRksXrClsQ6nnaFRfQVkMimij5GEvAMaXdYw=="
+    },
     "vue-hot-reload-api": {
       "version": "2.3.4",
       "resolved": "https://registry.npmmirror.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",

+ 3 - 0
package.json

@@ -10,6 +10,7 @@
     "core-js": "^3.8.3",
     "element-ui": "^2.15.8",
     "vue": "^2.6.14",
+    "vue-cropper": "^0.5.8",
     "vue-router": "^3.5.1",
     "vuex": "^3.6.2"
   },
@@ -18,6 +19,8 @@
     "@vue/cli-plugin-router": "~5.0.0",
     "@vue/cli-plugin-vuex": "~5.0.0",
     "@vue/cli-service": "~5.0.0",
+    "sass": "^1.54.4",
+    "sass-loader": "^13.0.2",
     "vue-template-compiler": "^2.6.14"
   },
   "browserslist": [

BIN
src/assets/imgs/add_photo_img.png


BIN
src/assets/imgs/profile.jpg


+ 2 - 0
src/main.js

@@ -4,9 +4,11 @@ import 'element-ui/lib/theme-chalk/index.css';
 import App from './App.vue'
 import router from './router'
 import store from './store'
+import VueCropper from 'vue-cropper'
 
 Vue.config.productionTip = false
 Vue.use(ElementUI);
+Vue.use(VueCropper)
 
 new Vue({
   router,

+ 230 - 0
src/views/user/personalCenter/changeAvatar.vue

@@ -0,0 +1,230 @@
+<template>
+  <div class="changeAvatarBox">
+    <el-dialog
+      title="修改头像"
+      :visible.sync="isShow"
+      width="55%"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      :before-close="handleClose"
+    >
+      <div class="dialogContent">
+        <div>
+          <!-- 要注意的是,组件的外部一定要设置固定的宽高,不然没东西-->
+          <div class="crop-box">
+            <vueCropper
+              ref="cropper"
+              :img="option.img"
+              :outputSize="option.outputSize"
+              :outputType="option.outputType"
+              :autoCrop="true"
+              :fixed="true"
+              :autoCropWidth="option.autoCropWidth"
+              :autoCropHeight="option.autoCropHeight"
+              :mode="option.mode"
+              @realTime="realTime"
+            ></vueCropper>
+          </div>
+          <div class="footerTools">
+            <label
+              class="toolsBtn"
+              for="uploads"
+              style="background: #f38e81; padding: 5px 10px; border-radius: 3px"
+              >上传图像</label
+            >
+            <input
+              type="file"
+              class="toolsBtn"
+              ref="input"
+              id="uploads"
+              style="position: absolute; clip: rect(0 0 0 0)"
+              @change="selectImg"
+            />
+            <div>
+              <span
+                @click="changeScale(-3)"
+                class="toolsBtn"
+                style="
+                  display: inline-block;
+                  width: 76px;
+                  height: 29px;
+                  line-height: 29px;
+                  text-align: center;
+                  background: #f38e81;
+                  border-radius: 3px;
+                "
+                >-</span
+              >
+              <span
+                @click="changeScale(3)"
+                class="toolsBtn"
+                style="
+                  display: inline-block;
+                  width: 76px;
+                  height: 29px;
+                  line-height: 29px;
+                  text-align: center;
+                  background: #f38e81;
+                  border-radius: 3px;
+                  margin-left: 19px;
+                "
+                >+</span
+              >
+            </div>
+          </div>
+        </div>
+
+        <!--预览效果图-->
+        <div class="show-preview">
+          <template v-if="option.img">
+            <div :style="previewStyle64" class="preview">
+              <img :src="previews.url" :style="previews.img" />
+            </div>
+            <p>64px*64px</p>
+            <div :style="previewStyle128" class="preview">
+              <img :src="previews.url" :style="previews.img" />
+            </div>
+            <p>128px*128px</p>
+            <div :style="previewStyle180" class="preview">
+              <img :src="previews.url" :style="previews.img" />
+            </div>
+            <p>180px*180px</p>
+          </template>
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="cancel">取 消</el-button>
+        <el-button type="primary" @click="confirm">确 定</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "changeAvatar",
+  props: ["isShow"],
+  data() {
+    return {
+      option: {
+        img: "",
+        outputSize: 1,
+        outputType: "",
+        autoCropWidth: "200",
+        autoCropHeight: "200",
+        mode: "cover",
+      },
+      previews: "", //图片预览
+      previewStyle64: "",
+      previewStyle128: "",
+      previewStyle180: "",
+    };
+  },
+  methods: {
+    selectImg(e) {
+      console.log(e);
+      let file = e.target.files[0];
+      this.option.img = URL.createObjectURL(file);
+    },
+    //图片缩放
+    changeScale(num) {
+      num = num || 1;
+      this.$refs.cropper.changeScale(num);
+    },
+    realTime(data) {
+      // console.log(data);
+      this.previews = data;
+
+      // 固定为 64 宽度
+      this.previewStyle64 = {
+        width: data.w + "px",
+        height: data.h + "px",
+        overflow: "hidden",
+        margin: "0",
+        zoom: 64 / data.w,
+      };
+      // 固定为 128 宽度
+      this.previewStyle128 = {
+        width: data.w + "px",
+        height: data.h + "px",
+        overflow: "hidden",
+        margin: "0",
+        zoom: 128 / data.w,
+      };
+      // 固定为 180 宽度
+      this.previewStyle180 = {
+        width: data.w + "px",
+        height: data.h + "px",
+        overflow: "hidden",
+        margin: "0",
+        zoom: 180 / data.w,
+      };
+    },
+    handleClose() {
+      this.$emit("closeShow");
+      this.previews = "";
+      this.option.img = "";
+      this.$refs.input.value="";
+    },
+    cancel() {
+      this.handleClose();
+    },
+    confirm() {
+      // 这里可以获取到裁剪完之后的  blob 数据和base64 数据两种,到时候看后端需要哪种
+      //   FormData
+      this.$refs.cropper.getCropBlob((data) => {
+        console.log(data)
+        // do something
+        // console.log(data);
+        // let formData = new FormData();
+        // formData.append("file");
+      });
+      this.handleClose();
+    },
+  },
+  mounted() {
+  },
+};
+</script>
+
+<style scoped>
+::v-deep .el-dialog__header {
+  font-weight: 800;
+}
+.dialogContent {
+  display: flex;
+  justify-content: space-around;
+}
+.crop-box {
+  width: 400px;
+  height: 400px;
+}
+.footerTools {
+  margin-top: 20px;
+  display: flex;
+  justify-content: space-between;
+}
+.show-preview {
+  width: 200px;
+  height: 450px;
+  border: 1px solid #dddddd;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding-top: 18px;
+}
+.preview {
+  overflow: hidden;
+
+  background: #cccccc;
+  border-radius: 50%;
+}
+.toolsBtn {
+  color: #ffffff;
+}
+.toolsBtn:hover {
+  cursor: pointer;
+  user-select: none;
+  background: #ef958a !important;
+}
+</style>

+ 237 - 2
src/views/user/personalCenter/personalCenter.vue

@@ -1,12 +1,247 @@
 <template>
-  <div class=""></div>
+  <div class="personalCenterBox">
+    <el-row>
+      <el-col :span="6" class="left">
+        <div class="leftbox">
+          <div class="leftboxTop">个人资料</div>
+          <div class="leftboxCon">
+            <p style="display:flex;align-items:center;justify-content:center;padding-top:18px">
+              <img src="@/assets/imgs/add_photo_img.png" alt="" style="width:120px;height:120px;border-radius:50%">
+            </p>
+            <div style="text-align:center;color:#337ab7;font-size:15px" ><span class="changeHead" style="cursor:pointer" @click="changeAvatar">修改头像</span> </div>
+            <ul style="list-style:none;padding:0 25px 30px">
+              <li style="display:flex;justify-content:space-between;height:40px;line-height:40px;border-top:1px solid #e7eaec;font-weight: 400;color:rgba(0,0,0,.85)">
+                <div>
+                  <i class="el-icon-user-solid"></i>
+                <span>登录名称:</span>
+                </div>
+                <div>admin</div>
+              </li>
+                  <li style="display:flex;justify-content:space-between;height:40px;line-height:40px;border-top:1px solid #e7eaec;font-weight: 400;color:rgba(0,0,0,.85)">
+                <div>
+                  <i class="el-icon-phone"></i>
+                <span>手机号码:</span>
+                </div>
+                <div>15638932672</div>
+              </li>
+                   <li style="display:flex;justify-content:space-between;height:40px;line-height:40px;border-top:1px solid #e7eaec;font-weight: 400;color:rgba(0,0,0,.85)">
+                <div>
+                  <i class="el-icon-s-shop"></i>
+                <span>所属机构:</span>
+                </div>
+                <div>安徽省</div>
+              </li>
+                    <li style="display:flex;justify-content:space-between;height:40px;line-height:40px;border-top:1px solid #e7eaec;font-weight: 400;color:rgba(0,0,0,.85)">
+                <div>
+                  <i class="el-icon-message"></i>
+                <span>邮箱地址:</span>
+                </div>
+                <div>ry@qq.com</div>
+              </li>
+                  <li style="display:flex;justify-content:space-between;height:40px;line-height:40px;border-top:1px solid #e7eaec;font-weight: 400;color:rgba(0,0,0,.85)">
+                <div>
+                  <i class="el-icon-date"></i>
+                <span>创建时间:</span>
+                </div>
+                <div>2018-03-16</div>
+              </li>
+            </ul>
+          </div>
+        </div>
+      </el-col>
+      <el-col :span="17" class="right">
+        <div class="rightbox">
+          <div class="rightboxTop">基本资料</div>
+          <div class="rightboxCon">
+            <div class="basicInfo">
+              <div
+                class="header"
+                style="
+                  color: #6f63dd;
+                  font-weight: 700;
+                  font-size: 14px;
+                  border-left: 2px solid #6f63dd;
+                  padding-left: 13px;
+                  margin-bottom:30px;
+                "
+              >
+                基本资料
+              </div>
+              <el-form ref="basicInfoForm" :model="basicInfoForm" label-width="80px" style="margin-left:60px">
+                <el-form-item label="用户名称:">
+                  <el-input
+                    v-model="basicInfoForm.name"
+                    size="small"
+                  ></el-input>
+                </el-form-item>
+                <el-form-item label="邮箱:">
+                  <el-input
+                    v-model="basicInfoForm.email"
+                    size="small"
+                  ></el-input>
+                </el-form-item>
+                <el-form-item label="性别:">
+                  <el-radio-group v-model="basicInfoForm.sex">
+                    <el-radio label="男"></el-radio>
+                    <el-radio label="女"></el-radio>
+                  </el-radio-group>
+                </el-form-item>
+                <el-form-item label="维护:">
+                  <el-radio-group v-model="basicInfoForm.safeguard ">
+                    <el-radio label="是"></el-radio>
+                    <el-radio label="否"></el-radio>
+                  </el-radio-group>
+                </el-form-item>
+                  <el-button type="success" @click="saveInfo" icon="el-icon-check" size="small"
+                    >保存</el-button
+                  >
+                  <el-button type="danger" @click="closeInfo" icon="el-icon-close" size="small">关闭</el-button>
+                </el-form-item>
+              </el-form>
+            </div>
+            <div class="changePass">
+             <div
+                class="header"
+                style="
+                  color: #6f63dd;
+                  font-weight: 700;
+                  font-size: 14px;
+                  border-left: 2px solid #6f63dd;
+                  padding-left: 13px;
+                  margin-top:15px;
+                "
+              >
+                修改密码
+             </div>
+               <el-form ref="changePassForm" :model="changePassForm" label-width="80px" style="margin-left:60px">
+                <el-form-item label="旧密码:">
+                  <el-input
+                    v-model="changePassForm.oldPass"
+                    size="small"
+                    placeholder="请输入旧密码"
+                  ></el-input>
+                </el-form-item>
+                <el-form-item label="新密码:">
+                  <el-input
+                    v-model="changePassForm.newPass"
+                    size="small"
+                     placeholder="请输入新密码"
+                  ></el-input>
+                </el-form-item>
+                  <el-form-item label="确认密码:">
+                  <el-input
+                    v-model="changePassForm.ackNewPass"
+                    size="small"
+                     placeholder="请确认密码"
+                  ></el-input>
+                </el-form-item>
+
+                  <el-button type="success" @click="saveChangePass" icon="el-icon-check" size="small"
+                    >保存</el-button
+                  >
+                  <el-button type="danger" @click="closeChangePass" icon="el-icon-close" size="small" >关闭</el-button>
+                </el-form-item>
+              </el-form>
+             </div>
+          </div>
+        </div>
+      </el-col>
+    </el-row>
+    <change-avatar :isShow="isShow" @closeShow="closeShow"></change-avatar>
+  </div>
 </template>
 
 <script>
+import changeAvatar from "./changeAvatar.vue";
 export default {
-  name:"personalCenter",
+  name: "personalCenter",
+  components: {
+    changeAvatar,
+  },
+  data() {
+    return {
+      basicInfoForm: {
+        name: "",
+        email: "",
+        sex: "",
+        safeguard: "",
+      },
+      changePassForm: {
+        oldPass: "",
+        newPass: "",
+        ackNewPass: "",
+      },
+      isShow: false, //父传子,控制弹出层的显隐
+    };
+  },
+  methods: {
+    // 基本资料
+    saveInfo() {
+      console.log("submit!");
+    },
+    closeInfo() {},
+
+    // 修改密码
+    saveChangePass() {},
+    closeChangePass() {},
+
+    // 修改头像
+    changeAvatar() {
+      this.isShow = true;
+    },
+    closeShow() {
+      this.isShow = false;
+    },
+  },
+  mounted() {},
 };
 </script>
 
 <style scoped>
+.personalCenterBox .left {
+  border: 1px solid #dddddd;
+  border-radius: 3px;
+}
+.personalCenterBox .left .leftbox {
+}
+
+.personalCenterBox .left .leftbox .leftboxTop {
+  background-color: #ebeffa;
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+  height: 41px;
+  line-height: 41px;
+  color: #333;
+  font-size: 14px;
+  padding-left: 10px;
+}
+
+.personalCenterBox .left .leftbox .leftboxCon {
+  background: #fff;
+}
+.personalCenterBox .right {
+  border: 1px solid #dddddd;
+  margin-left: 18px;
+  border-radius: 3px;
+}
+
+.personalCenterBox .right .rightbox {
+}
+.personalCenterBox .right .rightbox .rightboxTop {
+  background-color: #aaaaaa;
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+  height: 41px;
+  line-height: 41px;
+  color: #333;
+  font-size: 14px;
+  padding-left: 10px;
+}
+.personalCenterBox .right .rightbox .rightboxCon {
+  background: #fff;
+  padding: 20px;
+}
+.changeHead:hover {
+  color: rgba(0, 0, 0, 0.5) !important;
+}
 </style>