index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. <template>
  2. <div class="app-container user-info" v-if="pageType">
  3. <div class="title-max-box">个人信息</div>
  4. <div class="user-max-box">
  5. <div class="left-user-box">
  6. <userAvatar :user="user" />
  7. </div>
  8. <div class="right-user-box">
  9. <div class="text-box">
  10. <p>用户名称:<span>{{user.nickName}}</span></p>
  11. </div>
  12. <div class="text-box">
  13. <p>联系方式:<span>{{user.phonenumber?user.phonenumber:'未填写'}}</span><span @click="phoneButton(1)">编辑</span></p>
  14. </div>
  15. <div class="text-box" v-if="user.dept">
  16. <p>学院:<span>{{user.dept.deptName}}</span></p>
  17. </div>
  18. <div class="text-box">
  19. <p>角色:<span>{{roleGroup}}</span></p>
  20. </div>
  21. <div class="text-box">
  22. <p>创建日期:<span>{{user.createTime}}</span></p>
  23. </div>
  24. <div class="text-box">
  25. <p>创建日期:<span>{{user.createTime}}</span></p>
  26. </div>
  27. <div>
  28. <div class="up-data-box">
  29. <div class="up-data-min-box" style="display: flex;">
  30. <p class="up-data-title">人脸照片:</p>
  31. <div class="up-data-button" v-if="!user.faceImg" @click="upFaceOpenClick(2)">
  32. <p>+</p>
  33. <p>上传</p>
  34. </div>
  35. <img class="img-one" :src="user.faceImg" v-if="user.faceImg" @click="upFaceOpenClick(2)">
  36. </div>
  37. </div>
  38. <div class="up-data-box">
  39. <div class="up-data-min-box" style="display: flex;">
  40. <p class="up-data-title">电子签名:</p>
  41. <el-upload
  42. class="position-button"
  43. :action="uploadImgUrlTwo"
  44. :show-file-list="false"
  45. :auto-upload="false"
  46. :on-change="signatureChange"
  47. accept="image/jpeg,image/gif,image/png"
  48. :headers="headers"
  49. :before-upload="beforeAvatarUpload">
  50. <div class="up-data-button" v-if="!user.signature">
  51. <p>+</p>
  52. <p>上传</p>
  53. </div>
  54. <img class="img-two" :src="user.signature" v-if="user.signature">
  55. </el-upload>
  56. </div>
  57. </div>
  58. </div>
  59. </div>
  60. </div>
  61. <div class="title-max-box">修改密码</div>
  62. <el-form class="pass-word-box" :model="form" ref="form" :rules="rules" >
  63. <el-form-item label="旧密码" prop="oldPassword" label-width="120px">
  64. <el-input type="password" v-model="form.oldPassword" placeholder="请输入旧密码"/>
  65. </el-form-item>
  66. <el-form-item label="新密码" prop="newPassword" label-width="120px">
  67. <el-input type="password" v-model="form.newPassword" placeholder="请输入新密码"/>
  68. </el-form-item>
  69. <el-form-item label="确认密码" prop="confirmPassword" label-width="140px">
  70. <el-input type="password" v-model="form.confirmPassword" placeholder="请确认密码"/>
  71. </el-form-item>
  72. <p class="for-button-box inquire-button-one" @click="submit">修改</p>
  73. </el-form>
  74. <!--修改手机号-->
  75. <el-dialog title="修改手机号" :visible.sync="open" width="500px" append-to-body>
  76. <el-form ref="phoneForm" :model="phoneForm" :rules="rules" label-width="80px">
  77. <el-form-item label="联系方式" prop="phone">
  78. <el-input v-model="phoneForm.phone" placeholder="请输入联系方式" maxLength="11"/>
  79. </el-form-item>
  80. </el-form>
  81. <div slot="footer" class="dialog-footer">
  82. <el-button @click="phoneButton(2)">取 消</el-button>
  83. <el-button type="primary" @click="phoneButton(3)">确 定</el-button>
  84. </div>
  85. </el-dialog>
  86. <!--电子签名-->
  87. <el-dialog class="up-img-box" title="上传电子签名" :visible.sync="upImgOpen" width="600px" append-to-body>
  88. <p>示例</p>
  89. <img class="img-one" src="@/assets/ZDimages/icon_scdzqm_sl.png">
  90. <p>正楷签名</p>
  91. <div class="cropper-box">
  92. <vueCropper
  93. ref="cropper"
  94. :img="option.img"
  95. :outputSize="option.outputSize"
  96. :outputType="option.outputType"
  97. :info="option.info"
  98. :canScale="option.canScale"
  99. :autoCrop="option.autoCrop"
  100. :autoCropWidth="option.autoCropWidth"
  101. :autoCropHeight="option.autoCropHeight"
  102. :fixed="option.fixed"
  103. :fixedNumber="option.fixedNumber"
  104. :full="option.full"
  105. :fixedBox="option.fixedBox"
  106. :canMove="option.canMove"
  107. :canMoveBox="option.canMoveBox"
  108. :original="option.original"
  109. :centerBox="option.centerBox"
  110. :height="option.height"
  111. :infoTrue="option.infoTrue"
  112. :maxImgSize="option.maxImgSize"
  113. :enlarge="option.enlarge"
  114. :mode="option.mode"
  115. @realTime="realTime"
  116. @imgLoad="imgLoad"
  117. ></vueCropper>
  118. <p class="cropper-button" @click="upImgButton">保存查看</p>
  119. <el-upload
  120. class="position-button"
  121. :action="uploadImgUrl"
  122. :show-file-list="false"
  123. :auto-upload="false"
  124. :on-change="signatureChange"
  125. accept="image/jpeg,image/gif,image/png"
  126. :headers="headers"
  127. :before-upload="beforeAvatarUpload">
  128. <p style="position: absolute;right:100px;top:10px;z-index:1;color:#fff;background:#14AE10;cursor: pointer;padding:5px 10px;margin:0;border-radius:6px;">选择签名</p>
  129. </el-upload>
  130. </div>
  131. <p style="color:#999;">请将签名置于选择框内以便提高识别度</p>
  132. <img class="cropper-img" v-if="signatureData" :src="signatureData">
  133. <div slot="footer" class="dialog-footer">
  134. <el-button @click="upImgOpenClick(1)">取 消</el-button>
  135. <el-button type="primary" @click="upSignatureData">确 定</el-button>
  136. </div>
  137. </el-dialog>
  138. <!--上传照片-->
  139. <el-dialog class="up-img-box" title="上传照片" :visible.sync="upFaceOpen" width="600px" append-to-body>
  140. <el-upload
  141. ref="faceUpLoad"
  142. class="position-button"
  143. :action="uploadImgUrl"
  144. :show-file-list="false"
  145. :auto-upload="false"
  146. :on-change="faceChange"
  147. accept="image/jpeg,image/gif,image/png"
  148. :on-success="(res)=>handleAvatarSuccess(res)"
  149. :headers="headers"
  150. :before-upload="beforeAvatarUpload">
  151. <div v-if="!upFaceUrl" style="width:300px;height:300px;border: 1px dashed #E0E0E0;cursor: pointer;margin:20px 130px 0;">
  152. <p style="text-align: center;color:#999;font-weight:500;font-size: 20px;line-height:300px;margin:0;">+</p>
  153. </div>
  154. <img :src="upFaceUrl" v-if="upFaceUrl" style="width:300px;height:300px;border: 1px dashed #E0E0E0;cursor: pointer;margin:20px 130px 0;">
  155. </el-upload>
  156. <div slot="footer" class="dialog-footer">
  157. <el-button @click="faceButton(1)">取 消</el-button>
  158. <el-button type="primary" @click="faceButton(2)">确 定</el-button>
  159. </div>
  160. </el-dialog>
  161. </div>
  162. </template>
  163. <script>
  164. import userAvatar from "./userAvatar";
  165. import userInfo from "./userInfo";
  166. import resetPwd from "./resetPwd";
  167. import { getUserProfile,updateUserPwd,changePhone,genSign,updateSignature } from "@/api/system/user";
  168. import { getToken } from "@/utils/auth";
  169. export default {
  170. name: "Profile",
  171. components: {
  172. userAvatar,
  173. userInfo,
  174. resetPwd,
  175. },
  176. data() {
  177. const equalToPassword = (rule, value, callback) => {
  178. if (this.form.newPassword !== value) {
  179. callback(new Error("两次输入的密码不一致"));
  180. } else {
  181. callback();
  182. }
  183. };
  184. return {
  185. uploadImgUrl: window.location.href.split('://')[0]+'://' + process.env.VUE_APP_BASE_API + "/laboratory/studentinfo/commit/face", // 上传的图片服务器地址
  186. uploadImgUrlTwo: window.location.href.split('://')[0]+'://' + process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
  187. headers: {
  188. Authorization: "Bearer " + getToken(),
  189. },
  190. pageType:false,
  191. user: {},
  192. roleGroup: {},
  193. postGroup: {},
  194. activeTab: "resetPwd",
  195. form:{
  196. oldPassword:"",
  197. newPassword:"",
  198. confirmPassword:""
  199. },
  200. open:false,
  201. phoneForm:{
  202. phone:"",
  203. },
  204. // 表单校验
  205. rules: {
  206. oldPassword: [
  207. { required: true, message: "旧密码不能为空", trigger: "blur" },
  208. { required: true, message: "旧密码不能为空", validator: this.spaceJudgment, trigger: "blur" }
  209. ],
  210. newPassword: [
  211. { required: true, message: "新密码不能为空", trigger: "blur" },
  212. { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" },
  213. { required: true, message: "新密码不能为空", validator: this.spaceJudgment, trigger: "blur" }
  214. ],
  215. confirmPassword: [
  216. { required: true, message: "确认密码不能为空", trigger: "blur" },
  217. { required: true, validator: equalToPassword, trigger: "blur" },
  218. { required: true, message: "确认密码不能为空", validator: this.spaceJudgment, trigger: "blur" }
  219. ],
  220. phone: [
  221. { required: true, message: "请输入11位联系方式", trigger: "blur" },
  222. { validator: this.checkPhone, trigger: 'blur' },
  223. { min: 11, max: 11, message: "请输入11位联系方式", trigger: "blur" },
  224. { required: true, message: "请输入11位联系方式", validator: this.spaceJudgment, trigger: "blur" }
  225. ],
  226. },
  227. //上传签名开关
  228. upImgOpen:false,
  229. option:{
  230. img: '', // 裁剪图片的地址
  231. outputSize: 1, //裁剪生成图片的质量(可选0.1 - 1)
  232. outputType: 'png', //裁剪生成图片的格式(jpeg || png || webp)
  233. info: true, //图片大小信息
  234. canScale: true, //图片是否允许滚轮缩放
  235. autoCrop: true, //是否默认生成截图框
  236. autoCropWidth: 240, //默认生成截图框宽度
  237. autoCropHeight: 80, //默认生成截图框高度
  238. fixed: true, //是否开启截图框宽高固定比例
  239. fixedNumber: [3, 1], //截图框的宽高比例
  240. full: false, //false按原比例裁切图片,不失真
  241. fixedBox: true, //固定截图框大小,不允许改变
  242. canMove: false, //上传图片是否可以移动
  243. canMoveBox: true, //截图框能否拖动
  244. original: false, //上传图片按照原始比例渲染
  245. centerBox: false, //截图框是否被限制在图片里面
  246. height: true, //是否按照设备的dpr 输出等比例图片
  247. infoTrue: false, //true为展示真实输出图片宽高,false展示看到的截图框宽高
  248. maxImgSize: 3000, //限制图片最大宽度和高度
  249. enlarge: 1, //图片根据截图框输出比例倍数
  250. mode: '560px 400px' //图片默认渲染方式
  251. },
  252. previews:{},
  253. //上传人脸
  254. upFaceOpen:false,
  255. upFaceUrl:"",
  256. //临时签名数据
  257. signatureData:"",
  258. };
  259. },
  260. created() {
  261. this.getUser();
  262. },
  263. methods: {
  264. //上传签名
  265. upSignatureData(){
  266. if(!this.signatureData){
  267. this.msgError('请先选择签名上传并保存查看')
  268. }
  269. var blob = this.dataURLtoBlob(this.signatureData);
  270. var file = this.blobToFile(blob, 'dx.jpg');
  271. let formData = new FormData();
  272. formData.append('file',file,"DX.jpg")
  273. console.log("formData",formData);
  274. updateSignature(formData).then(response => {
  275. if(response.code == 200){
  276. this.msgSuccess("操作成功");
  277. this.upImgOpen = false;
  278. this.getUser();
  279. }
  280. });
  281. },
  282. //照片页面开关
  283. upFaceOpenClick(type){
  284. if(type == 1){
  285. this.upFaceOpen = false;
  286. }else if (type == 2){
  287. this.upFaceUrl = this.user.faceImg;
  288. this.upFaceOpen = true;
  289. }
  290. },
  291. //签名页面开关
  292. upImgOpenClick(type){
  293. if(type == 1){
  294. this.upImgOpen = false;
  295. }else if (type == 2){
  296. this.option.img = this.user.signature;
  297. this.signatureData = this.user.signature;
  298. this.upImgOpen = true;
  299. }
  300. },
  301. //确定签名
  302. upImgButton(){
  303. let self = this;
  304. this.$refs.cropper.getCropBlob(async (data) => {
  305. let formData = new FormData();
  306. formData.append('file',data,"DX.jpg")
  307. genSign(formData).then(response => {
  308. if(response.code == 200){
  309. this.signatureData = 'data:image/png;base64,'+response.data;
  310. } else {
  311. this.msgError(response.msg)
  312. }
  313. });
  314. })
  315. },
  316. //照片选择
  317. faceChange(val){
  318. const windowURL = window.URL || window.webkitURL;
  319. this.upFaceUrl = windowURL.createObjectURL(val.raw)
  320. },
  321. //签名选择
  322. signatureChange(val){
  323. const windowURL = window.URL || window.webkitURL;
  324. this.option.img = windowURL.createObjectURL(val.raw)
  325. this.signatureData = "";
  326. this.upImgOpen = true;
  327. },
  328. // 照片上传按钮
  329. faceButton(type){
  330. if(type==1){
  331. this.upFaceOpen = false;
  332. }else if(type == 2){
  333. this.$refs.faceUpLoad.submit();
  334. }
  335. },
  336. //上传
  337. handleAvatarSuccess(res, type) {
  338. if(res.code == 200){
  339. this.user.faceImg = res.data.cardUrl;
  340. this.upFaceOpen = false;
  341. this.msgSuccess(res.msg)
  342. this.$forceUpdate()
  343. }else{
  344. this.msgError(res.msg)
  345. }
  346. },
  347. beforeAvatarUpload(file) {
  348. let type = false;
  349. if (file.type == 'image/png' || file.type == 'image/jpeg' || file.type == 'image/gif') {
  350. type = true;
  351. }else{
  352. this.$message.error('只能上传png/jpeg/gif格式图片');
  353. type = false;
  354. }
  355. return type;
  356. },
  357. // 实时预览函数
  358. realTime(data) {
  359. this.previews = data;
  360. },
  361. //图片加载的回调 imgLoad 返回结果success, error
  362. imgLoad (msg) {
  363. // console.log('imgLoad')
  364. // console.log(msg)
  365. },
  366. //修改电话按钮
  367. phoneButton(type){
  368. let self = this;
  369. if(this.phoneType != type){
  370. if(type == 1){
  371. this.$set(this.phoneForm,'phone',this.user.phonenumber);
  372. this.open = true;
  373. }else if(type == 2){
  374. this.$set(this.phoneForm,'phone',"");
  375. this.open = false;
  376. }else if(type == 3){
  377. self.$refs["phoneForm"].validate(valid => {
  378. if (valid) {
  379. this.$confirm('确定要修改吗', "警告", {
  380. confirmButtonText: "确定",
  381. cancelButtonText: "取消",
  382. type: "warning"
  383. }).then(function() {
  384. self.upPhoneData();
  385. }).then(() => {
  386. }).catch(() => {});
  387. }
  388. });
  389. }
  390. }
  391. },
  392. //手机修改接口
  393. upPhoneData(){
  394. changePhone({phonenumber:this.phoneForm.phone}).then(response => {
  395. this.$set(this.phoneForm,'phone',"");
  396. this.open = false;
  397. this.getUser();
  398. this.msgSuccess("修改成功")
  399. });
  400. },
  401. //手机号验证
  402. checkPhone(rule, value, callback) {
  403. if (!value) {
  404. return callback(new Error('不能为空'))
  405. } else {
  406. const reg = /^1[3|4|5|7|8|9][0-9]\d{8}$/
  407. if (reg.test(value)) {
  408. callback()
  409. } else {
  410. return callback(new Error('请输入正确的联系方式'))
  411. }
  412. }
  413. },
  414. //修改按钮密码
  415. submit() {
  416. let self = this;
  417. self.$refs["form"].validate(valid => {
  418. if (valid) {
  419. this.$confirm('确定要修改吗', "警告", {
  420. confirmButtonText: "确定",
  421. cancelButtonText: "取消",
  422. type: "warning"
  423. }).then(function() {
  424. self.updateUserPwd();
  425. }).then(() => {
  426. }).catch(() => {});
  427. }
  428. });
  429. },
  430. //修改密码接口
  431. updateUserPwd(){
  432. updateUserPwd(this.form.oldPassword, this.form.newPassword).then(
  433. response => {
  434. this.form.oldPassword = "";
  435. this.form.newPassword = "";
  436. this.form.confirmPassword = "";
  437. this.msgSuccess("修改成功");
  438. }
  439. );
  440. },
  441. //获取信息
  442. getUser() {
  443. getUserProfile().then(response => {
  444. this.user = response.data;
  445. this.roleGroup = response.roleGroup;
  446. this.postGroup = response.postGroup;
  447. this.pageType = true;
  448. });
  449. },
  450. //将base64转换为blob
  451. dataURLtoBlob: function(dataurl) {
  452. var arr = dataurl.split(',')
  453. var mime = arr[0].match(/:(.*?);/)[1]
  454. var bstr = atob(arr[1])
  455. var n = bstr.length
  456. var u8arr = new Uint8Array(n)
  457. while (n--) {
  458. u8arr[n] = bstr.charCodeAt(n);
  459. }
  460. return new Blob([u8arr], { type: mime });
  461. },
  462. //将blob转换为file
  463. blobToFile: function(theBlob, fileName){
  464. theBlob.lastModifiedDate = new Date();
  465. theBlob.name = fileName;
  466. return theBlob;
  467. },
  468. }
  469. };
  470. </script>
  471. <style lang="scss" scoped>
  472. .user-info{
  473. display: flex!important;
  474. flex-direction: column;
  475. box-shadow: 0 0 8px 2px rgba(0, 0, 0, 0.1);
  476. padding:0 20px 15px!important;
  477. *{
  478. margin:0;
  479. padding:0;
  480. }
  481. .title-max-box{
  482. font-size:18px;
  483. color:#0045AF;
  484. line-height:80px;
  485. border-bottom:1px solid #E0E0E0;
  486. }
  487. .user-max-box{
  488. display: flex;
  489. .left-user-box{
  490. }
  491. .right-user-box{
  492. padding-top:42px;
  493. .text-box{
  494. display: inline-block;
  495. width:380px;
  496. height:20px;
  497. line-height:20px;
  498. margin-bottom:30px;
  499. p:nth-child(1){
  500. font-size:15px;
  501. color:#333;
  502. span{
  503. color:#999;
  504. }
  505. span:nth-child(2){
  506. margin-left:70px;
  507. font-size:15px;
  508. color:#0045AF;
  509. cursor: pointer;
  510. }
  511. }
  512. }
  513. .up-data-box{
  514. display: inline-block;
  515. width:380px;
  516. line-height:20px;
  517. margin-bottom:30px;
  518. .up-data-min-box{
  519. .up-data-title{
  520. font-size:15px;
  521. color:#333;
  522. }
  523. .up-data-button{
  524. width:120px;
  525. height:120px;
  526. border: 1px dashed #E0E0E0;
  527. cursor: pointer;
  528. p{
  529. text-align: center;
  530. color:#999;
  531. font-weight:500;
  532. }
  533. p:nth-child(1){
  534. font-size: 20px;
  535. line-height:40px;
  536. margin-top:20px;
  537. }
  538. p:nth-child(2){
  539. font-size: 16px;
  540. }
  541. }
  542. .img-one{
  543. width:120px;
  544. height:120px;
  545. }
  546. .img-two{
  547. width: 240px;
  548. height:80px;
  549. }
  550. }
  551. }
  552. }
  553. }
  554. .pass-word-box{
  555. display: flex;
  556. padding:30px 0;
  557. .for-button-box{
  558. margin-left:50px;
  559. font-size:14px;
  560. }
  561. }
  562. .svg-icon{
  563. margin-right:10px;
  564. }
  565. }
  566. </style>
  567. <style lang="scss">
  568. .up-img-box{
  569. .el-dialog__body{
  570. padding-top:0;
  571. }
  572. .img-one{
  573. width:560px;
  574. height:150px;
  575. }
  576. .cropper-img{
  577. display: block;
  578. border:1px solid #e0e0e0;
  579. width:360px;
  580. height:120px;
  581. margin:0 auto;
  582. }
  583. .cropper-box{
  584. width:560px;
  585. height:270px;
  586. position: relative;
  587. .cropper-button{
  588. position: absolute;
  589. right:10px;top:10px;
  590. z-index:1;
  591. background: #0183FA;
  592. color:#fff;
  593. cursor: pointer;
  594. padding:5px 10px;
  595. margin:0;
  596. border-radius:6px;
  597. }
  598. }
  599. }
  600. </style>