index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  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: this.uploadUrl(), // 上传的图片服务器地址
  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. const file = new File([data], 'userImg.jpg', { type: 'image/jpeg', lastModified: Date.now() });
  306. let formData = new FormData();
  307. formData.append('file',file,"DX.jpg")
  308. genSign(formData).then(response => {
  309. if(response.code == 200){
  310. this.signatureData = 'data:image/png;base64,'+response.data;
  311. } else {
  312. this.msgError(response.msg)
  313. }
  314. });
  315. })
  316. },
  317. //照片选择
  318. faceChange(val){
  319. const windowURL = window.URL || window.webkitURL;
  320. this.upFaceUrl = windowURL.createObjectURL(val.raw)
  321. },
  322. //签名选择
  323. signatureChange(val){
  324. const windowURL = window.URL || window.webkitURL;
  325. this.option.img = windowURL.createObjectURL(val.raw)
  326. this.signatureData = "";
  327. this.upImgOpen = true;
  328. },
  329. // 照片上传按钮
  330. faceButton(type){
  331. if(type==1){
  332. this.upFaceOpen = false;
  333. }else if(type == 2){
  334. this.$refs.faceUpLoad.submit();
  335. }
  336. },
  337. //上传
  338. handleAvatarSuccess(res, type) {
  339. if(res.code == 200){
  340. this.user.faceImg = res.data.cardUrl;
  341. this.upFaceOpen = false;
  342. this.msgSuccess(res.msg)
  343. this.$forceUpdate()
  344. }else{
  345. this.msgError(res.msg)
  346. }
  347. },
  348. beforeAvatarUpload(file) {
  349. let type = false;
  350. if (file.type == 'image/png' || file.type == 'image/jpeg' || file.type == 'image/gif') {
  351. type = true;
  352. }else{
  353. this.$message.error('只能上传png/jpeg/gif格式图片');
  354. type = false;
  355. }
  356. return type;
  357. },
  358. // 实时预览函数
  359. realTime(data) {
  360. this.previews = data;
  361. },
  362. //图片加载的回调 imgLoad 返回结果success, error
  363. imgLoad (msg) {
  364. // console.log('imgLoad')
  365. // console.log(msg)
  366. },
  367. //修改联系方式按钮
  368. phoneButton(type){
  369. let self = this;
  370. if(this.phoneType != type){
  371. if(type == 1){
  372. this.$set(this.phoneForm,'phone',this.user.phonenumber);
  373. this.open = true;
  374. }else if(type == 2){
  375. this.$set(this.phoneForm,'phone',"");
  376. this.open = false;
  377. }else if(type == 3){
  378. self.$refs["phoneForm"].validate(valid => {
  379. if (valid) {
  380. this.$confirm('确定要修改吗', "警告", {
  381. confirmButtonText: "确定",
  382. cancelButtonText: "取消",
  383. type: "warning"
  384. }).then(function() {
  385. self.upPhoneData();
  386. }).then(() => {
  387. }).catch(() => {});
  388. }
  389. });
  390. }
  391. }
  392. },
  393. //手机修改接口
  394. upPhoneData(){
  395. changePhone({phonenumber:this.phoneForm.phone}).then(response => {
  396. this.$set(this.phoneForm,'phone',"");
  397. this.open = false;
  398. this.getUser();
  399. this.msgSuccess("修改成功")
  400. });
  401. },
  402. //手机号验证
  403. checkPhone(rule, value, callback) {
  404. if (!value) {
  405. return callback(new Error('不能为空'))
  406. } else {
  407. const reg = /^1[3|4|5|7|8|9][0-9]\d{8}$/
  408. if (reg.test(value)) {
  409. callback()
  410. } else {
  411. return callback(new Error('请输入正确的联系方式'))
  412. }
  413. }
  414. },
  415. //修改按钮密码
  416. submit() {
  417. let self = this;
  418. self.$refs["form"].validate(valid => {
  419. if (valid) {
  420. this.$confirm('确定要修改吗', "警告", {
  421. confirmButtonText: "确定",
  422. cancelButtonText: "取消",
  423. type: "warning"
  424. }).then(function() {
  425. self.updateUserPwd();
  426. }).then(() => {
  427. }).catch(() => {});
  428. }
  429. });
  430. },
  431. //修改密码接口
  432. updateUserPwd(){
  433. updateUserPwd(this.form.oldPassword, this.form.newPassword).then(
  434. response => {
  435. this.form.oldPassword = "";
  436. this.form.newPassword = "";
  437. this.form.confirmPassword = "";
  438. this.msgSuccess("修改成功");
  439. }
  440. );
  441. },
  442. //获取信息
  443. getUser() {
  444. getUserProfile().then(response => {
  445. this.user = response.data;
  446. this.roleGroup = response.roleGroup;
  447. this.postGroup = response.postGroup;
  448. this.pageType = true;
  449. });
  450. },
  451. //将base64转换为blob
  452. dataURLtoBlob: function(dataurl) {
  453. var arr = dataurl.split(',')
  454. var mime = arr[0].match(/:(.*?);/)[1]
  455. var bstr = atob(arr[1])
  456. var n = bstr.length
  457. var u8arr = new Uint8Array(n)
  458. while (n--) {
  459. u8arr[n] = bstr.charCodeAt(n);
  460. }
  461. return new Blob([u8arr], { type: mime });
  462. },
  463. //将blob转换为file
  464. blobToFile: function(theBlob, fileName){
  465. theBlob.lastModifiedDate = new Date();
  466. theBlob.name = fileName;
  467. return theBlob;
  468. },
  469. }
  470. };
  471. </script>
  472. <style lang="scss" scoped>
  473. .user-info{
  474. display: flex!important;
  475. flex-direction: column;
  476. box-shadow: 0 0 8px 2px rgba(0, 0, 0, 0.1);
  477. padding:0 20px 15px!important;
  478. *{
  479. margin:0;
  480. padding:0;
  481. }
  482. .title-max-box{
  483. font-size:18px;
  484. color:#0045AF;
  485. line-height:80px;
  486. border-bottom:1px solid #E0E0E0;
  487. }
  488. .user-max-box{
  489. display: flex;
  490. .left-user-box{
  491. }
  492. .right-user-box{
  493. padding-top:42px;
  494. .text-box{
  495. display: inline-block;
  496. width:380px;
  497. height:20px;
  498. line-height:20px;
  499. margin-bottom:30px;
  500. p:nth-child(1){
  501. font-size:15px;
  502. color:#333;
  503. span{
  504. color:#999;
  505. }
  506. span:nth-child(2){
  507. margin-left:70px;
  508. font-size:15px;
  509. color:#0045AF;
  510. cursor: pointer;
  511. }
  512. }
  513. }
  514. .up-data-box{
  515. display: inline-block;
  516. width:380px;
  517. line-height:20px;
  518. margin-bottom:30px;
  519. .up-data-min-box{
  520. .up-data-title{
  521. font-size:15px;
  522. color:#333;
  523. }
  524. .up-data-button{
  525. width:120px;
  526. height:120px;
  527. border: 1px dashed #E0E0E0;
  528. cursor: pointer;
  529. p{
  530. text-align: center;
  531. color:#999;
  532. font-weight:500;
  533. }
  534. p:nth-child(1){
  535. font-size: 20px;
  536. line-height:40px;
  537. margin-top:20px;
  538. }
  539. p:nth-child(2){
  540. font-size: 16px;
  541. }
  542. }
  543. .img-one{
  544. width:120px;
  545. height:120px;
  546. }
  547. .img-two{
  548. width: 240px;
  549. height:80px;
  550. }
  551. }
  552. }
  553. }
  554. }
  555. .pass-word-box{
  556. display: flex;
  557. padding:30px 0;
  558. .for-button-box{
  559. margin-left:50px;
  560. font-size:14px;
  561. }
  562. }
  563. .svg-icon{
  564. margin-right:10px;
  565. }
  566. }
  567. </style>
  568. <style lang="scss">
  569. .up-img-box{
  570. .el-dialog__body{
  571. padding-top:0;
  572. }
  573. .img-one{
  574. width:560px;
  575. height:150px;
  576. }
  577. .cropper-img{
  578. display: block;
  579. border:1px solid #e0e0e0;
  580. width:360px;
  581. height:120px;
  582. margin:0 auto;
  583. }
  584. .cropper-box{
  585. width:560px;
  586. height:270px;
  587. position: relative;
  588. .cropper-button{
  589. position: absolute;
  590. right:10px;top:10px;
  591. z-index:1;
  592. background: #0183FA;
  593. color:#fff;
  594. cursor: pointer;
  595. padding:5px 10px;
  596. margin:0;
  597. border-radius:6px;
  598. }
  599. }
  600. }
  601. </style>