Prechádzať zdrojové kódy

医生端代码提交

yjwang 1 týždeň pred
rodič
commit
1c73649768

+ 8 - 0
src/api/doctor.js

@@ -80,4 +80,12 @@ export function sendSmsCode() {
   })
 }
 
+export function editDoctorInfo(data) {
+  return request({
+    url: '/app/doctor/editDoctorInfo',
+    method: 'post',
+    data: data
+  })
+}
+
 

+ 6 - 1
src/api/store.js

@@ -10,7 +10,12 @@ export function getStoreList() {
 }
 
 
-
+export function getCitys() {
+  return request({
+    url: '/app/store/getCitys',
+    method: 'get'
+  })
+}
 
 
 

+ 269 - 72
src/views/doctor/profile/doctorInfo.vue

@@ -1,107 +1,228 @@
 <template>
   <div>
-  <el-form ref="form" :model="doctor" :rules="rules" label-width="120px">
-    <el-form-item label="头像" prop="avatar">
-
-    <img v-if="doctor.avatar" :src="doctor.avatar" class="avatar" width="200px">
-
-    </el-form-item>
-    <el-form-item :label="name" prop="doctorName">
-      <el-input v-model="doctor.doctorName" maxlength="30" readonly />
-    </el-form-item>
-    <el-form-item label="联系电话" prop="mobile">
-      <el-input v-model="doctor.mobile" maxlength="11" readonly/>
-    </el-form-item>
-    <el-form-item label="擅长领域" prop="speciality">
-      <el-input v-model="doctor.speciality" maxlength="50" readonly/>
-    </el-form-item>
-    <el-form-item label="所属店铺" prop="hospitalName">
-      <el-input v-model="hospital.hospitalName" maxlength="50" readonly/>
-    </el-form-item>
-    <el-form-item label="所属科室" prop="deptName">
-      <el-input v-model="department.deptName" maxlength="50" readonly/>
-    </el-form-item>
-    <el-form-item label="职称" prop="position">
-      <el-input v-model="doctor.position" maxlength="50" readonly/>
-    </el-form-item>
-    <el-form-item label="标签" prop="tags">
-      <el-input v-model="doctor.tags" maxlength="50" readonly/>
-    </el-form-item>
-    <el-form-item style="display: flex; justify-content: flex-end;">
-      <el-button v-if="doctor.doctorCardUrl" type="success" @click="handleCard()" style="margin-right: 10px;">名片</el-button>
-      <el-button type="primary" @click="handleDoctorDetails()" style="margin-right: 10px;">详情</el-button>
-      <el-button type="danger"  @click="close">关闭</el-button>
-    </el-form-item>
-  </el-form>
-  <el-drawer
-      :with-header="false"
-      size="75%"
-      :visible.sync="doctorItem.open">
-      <doctorDetails  ref="doctorDetails" :doctor="doctor" :hospital="hospital" :department="department"  />
-    </el-drawer>
-    <el-dialog :visible.sync="cardVisible"  width="30%">
-      <img v-if="doctor.doctorCardUrl" :src="doctor.doctorCardUrl" style="width: 100%;" >
-    </el-dialog>
+    <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+      <!-- 原有表单结构不变 -->
+      <el-form-item label="药师照片" prop="avatar">
+        <el-upload
+          :action="uploadUrl"
+          list-type="picture-card"
+          :file-list="avatarList"
+          :on-success="(response, file) => handleFileSuccess(response, file, 'avatar')"
+          :before-upload="beforeAvatarUpload"
+          :limit="1"
+          :on-remove="handleRemove"
+        >
+          <i class="el-icon-plus"></i>
+        </el-upload>
+      </el-form-item>
+      <el-form-item :label="name" prop="doctorName">
+        <el-input v-model="form.doctorName" maxlength="30"/>
+      </el-form-item>
+      <el-form-item label="联系电话" prop="mobile">
+        <el-input v-model="form.mobile" maxlength="11"/>
+      </el-form-item>
+      <el-form-item label="身份证号" prop="idCard">
+        <el-input v-model="form.idCard" maxlength="18"/>
+      </el-form-item>
+      <el-form-item label="所属城市" prop="cityIds">
+        <el-cascader
+          ref="citySelect"
+          v-model="form.cityIds"
+          :options="citys"
+          @change="handleCityChange">
+        </el-cascader>
+      </el-form-item>
+      <el-form-item label="所属店铺" prop="hospitalName">
+        <el-input v-model="form.hospitalName" maxlength="50" disabled/>
+      </el-form-item>
+      <el-form-item label="职称" prop="position">
+        <el-input v-model="form.position" maxlength="50" disabled/>
+      </el-form-item>
+      <el-form-item label="身份证正面" prop="idCardFrontUrl">
+        <el-upload
+          :action="uploadUrl"
+          list-type="picture-card"
+          :file-list="idCardFrontUrlList"
+          :on-success="(response, file) => handleFileSuccess(response, file, 'idCardFrontUrl')"
+          :before-upload="beforeAvatarUpload"
+          :limit="1"
+          :on-remove="handleIdRemove"
+        >
+          <i class="el-icon-plus"></i>
+        </el-upload>
+      </el-form-item>
+      <el-form-item label="身份证反面" prop="idCardBackUrl">
+        <el-upload
+          :action="uploadUrl"
+          list-type="picture-card"
+          :file-list="idCardBackUrlList"
+          :on-success="(response, file) => handleFileSuccess(response, file, 'idCardBackUrl')"
+          :before-upload="beforeAvatarUpload"
+          :limit="1"
+          :on-remove="handleIdBackRemove"
+        >
+          <i class="el-icon-plus"></i>
+        </el-upload>
+      </el-form-item>
+      <el-form-item label="职业证书" prop="practiseImages">
+        <el-upload
+          :action="uploadUrl"
+          list-type="picture-card"
+          :file-list="practiseImagesList"
+          :on-success="(response, file) => handleFileImgsSuccess(response, file, 'practiseImages')"
+          :before-upload="beforeAvatarUpload"
+          :limit="3"
+          :on-remove="handlPractiseImagesRemove"
+        >
+          <i class="el-icon-plus"></i>
+        </el-upload>
+      </el-form-item>
+      <el-form-item label="执业证编号" prop="practiseCode">
+        <el-input v-model="form.practiseCode" maxlength="50"/>
+      </el-form-item>
+      <el-form-item style="display: flex; justify-content: flex-end;">
+        <el-button type="primary"  @click="submit">保 存</el-button>
+        <el-button type="danger"  @click="close">关 闭</el-button>
+      </el-form-item>
+    </el-form>
   </div>
-
 </template>
 
 <script>
 import doctorDetails from '../../components/doctor/doctorDetails.vue';
+import {getCitys} from "@/api/store";
+import {editDoctorInfo} from '@/api/doctor'
 export default {
-  props: {
-    doctor: {},
-    hospital:{},
-    department:{},
-  },
   components: { doctorDetails},
   data() {
+    // 手机号验证规则
+    const validateMobile = (rule, value, callback) => {
+      if (!value) {
+        return callback(new Error('请输入联系电话'));
+      }
+      const reg = /^1[3-9]\d{9}$/;
+      if (!reg.test(value)) {
+        return callback(new Error('请输入正确的手机号'));
+      }
+      callback();
+    };
+
+    // 身份证号验证规则
+    const validateIdCard = (rule, value, callback) => {
+      if (!value) {
+        return callback(new Error('请输入身份证号'));
+      }
+      const reg = /(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
+      if (!reg.test(value)) {
+        return callback(new Error('请输入正确的身份证号'));
+      }
+      callback();
+    };
+
     return {
+      idCardFrontUrlList:[],
+      idCardBackUrlList:[],
+      practiseImagesList:[],
+      avatarList:[],
+      form:{
+        doctorId:null,
+        avatar:null,
+        cityIds:[],
+        doctorName:null,
+        storeName:null,
+        mobile:null,
+        idCard:null,
+        position:null,
+        practiseImages:null,
+        idCardFrontUrl:null,
+        idCardBackUrl:null,
+        practiseCode:null,
+      },
+      citys:[],
       name:'医生姓名',
       cardVisible: false,
       doctorItem:{
         open:false
       },
-      uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
-            baseUrl: process.env.VUE_APP_BASE_API,
-      // 表单校验
+      uploadUrl:process.env.VUE_APP_BASE_API+"app/common/uploadOSS",
+      baseUrl: process.env.VUE_APP_BASE_API,
+      // 表单校验规则(核心新增部分)
       rules: {
+        avatar: [
+          { required: true, message: '请上传药师照片', trigger: 'change' }
+        ],
+        doctorName: [
+          { required: true, message: '请输入姓名', trigger: 'blur' },
+          { min: 1, max: 30, message: '姓名长度在1-30个字符之间', trigger: 'blur' }
+        ],
+        mobile: [
+          { required: true, validator: validateMobile, trigger: 'blur' }
+        ],
+        idCard: [
+          { required: true, validator: validateIdCard, trigger: 'blur' }
+        ],
+        cityIds: [
+          { required: true, message: '请选择所属城市', trigger: 'change' }
+        ],
+        hospitalName: [
+
+        ],
+        position: [
+          { required: true, message: '职称不能为空', trigger: 'blur' }
+        ],
+        idCardFrontUrl: [
+          { required: true, message: '请上传身份证正面', trigger: 'change' }
+        ],
+        idCardBackUrl: [
+          { required: true, message: '请上传身份证反面', trigger: 'change' }
+        ],
+        practiseImages: [
+          { required: true, message: '请上传职业证书(最多3张)', trigger: 'change' }
+        ],
+        practiseCode: [
+          { required: true, message: '请输入执业证编号', trigger: 'blur' },
+          { min: 1, max: 50, message: '编号长度在1-50个字符之间', trigger: 'blur' }
+        ]
       }
     };
   },
   mounted(){
     this.getType();
+    this.getCitys();
+    this.loadData();
   },
   methods: {
+    // 原有方法不变,仅修正save按钮绑定的事件为submit
     handleCard() {
       this.cardVisible = true;
     },
     handleDoctorDetails(){
       this.doctorItem.open = true;
     },
-
-       handleAvatarSuccess(res, file) {
-            if(res.code==200){
-              this.doctor.logoUrl=res.url;
-              self.$forceUpdate()
-            }
-            else{
-              this.msgError(res.msg);
-            }
-        },
-        beforeAvatarUpload(file) {
-          const isLt1M = file.size / 1024 / 1024 < 1;
-          if (!isLt1M) {
-            this.$message.error('上传图片大小不能超过 1MB!');
-          }
-          return   isLt1M;
-        },
-
+    handleAvatarSuccess(res, file) {
+      if(res.code==200){
+        this.doctor.logoUrl=res.url;
+        this.$forceUpdate()
+      } else{
+        this.msgError(res.msg);
+      }
+    },
+    beforeAvatarUpload(file) {
+      const isLt1M = file.size / 1024 / 1024 < 1;
+      if (!isLt1M) {
+        this.$message.error('上传图片大小不能超过 1MB!');
+      }
+      return isLt1M;
+    },
     submit() {
       this.$refs["form"].validate(valid => {
         if (valid) {
-          editData(this.doctor).then(response => {
+          //处理拼接
+          this.form.cityIds = this.form.cityIds.join(",");
+          console.log(this.form);
+          editDoctorInfo(this.form).then(response => {
             this.msgSuccess("修改成功");
+            this.close();
           });
         }
       });
@@ -115,7 +236,83 @@ export default {
       if(type == 2){
         this.name = '药剂师姓名';
       }
-    }
-  }
+    },
+    getCitys() {
+      getCitys().then(res => {
+        this.citys = res.data;
+      })
+    },
+    handleCityChange(value) {
+      const nodes = this.$refs.citySelect.getCheckedNodes();
+      if (nodes.length) {
+        this.form.address = nodes[0].pathLabels.join('');
+        this.form.cityIds = value;
+      }
+    },
+    handleFileSuccess(response, file, field) {
+      if (response.code === 200) {
+        this.$set(this.form, field, response.url);
+        this.$forceUpdate();
+      } else {
+        this.msgError(response.msg);
+      }
+    },
+    handleFileImgsSuccess(response, file, field) {
+      if (response.code === 200) {
+        const newUrl = (response.url || '').trim();
+        if (!newUrl) {
+          this.$message.warning('上传成功,但未获取到有效URL');
+          return;
+        }
+        const currentValue = (this.form[field] || '').trim();
+        const newValue = currentValue ? `${currentValue},${newUrl}` : newUrl;
+        this.$set(this.form, field, newValue);
+        console.log(`字段[${field}]的拼接结果:`, this.form[field]);
+      } else {
+        this.$message.error(response.msg || '上传失败,请重试');
+      }
+    },
+    loadData(data){
+      if (!data || !data.doctor) return;
+      const doctor = data.doctor;
+      this.form.doctorId = doctor.doctorId;
+      this.form.avatar = doctor.avatar;
+      this.avatarList = doctor.avatar ? [{url: doctor.avatar}] : [];
+      this.form.doctorName = doctor.doctorName;
+      this.form.mobile = doctor.mobile;
+      this.form.idCard = doctor.idCard;
+      this.form.cityIds = doctor.cityIds ? doctor.cityIds.split(",").map(Number) : [];
+      this.form.hospitalName = data.storeName || '';
+      this.form.position = doctor.position || '';
+      this.form.idCardFrontUrl = doctor.idCardFrontUrl;
+      this.idCardFrontUrlList = doctor.idCardFrontUrl ? [{url: doctor.idCardFrontUrl}] : [];
+      this.form.idCardBackUrl = doctor.idCardBackUrl;
+      this.idCardBackUrlList = doctor.idCardBackUrl ? [{url: doctor.idCardBackUrl}] : [];
+      this.form.practiseCode = doctor.practiseCode || '';
+      this.form.practiseImages = doctor.practiseImages || '';
+      this.practiseImagesList = doctor.practiseImages
+        ? doctor.practiseImages.split(',').map(s => ({url: s.trim()})).filter(item => item.url)
+        : [];
+    },
+    handleRemove(file, fileList) {
+      this.avatarList = [];
+      this.form.avatar = null;
+    },
+    handleIdRemove(file, fileList) {
+      this.idCardFrontUrlList = [];
+      this.form.idCardFrontUrl = null;
+    },
+    handleIdBackRemove(file, fileList) {
+      this.idCardBackUrlList = [];
+      this.form.idCardBackUrl = null;
+    },
+    handlPractiseImagesRemove(file, fileList) {
+      this.practiseImagesList = fileList;
+      this.form.practiseImages = fileList
+        .map(item => item.url?.trim())
+        .filter(url => url)
+        .join(',');
+    },
+  },
 };
 </script>

+ 5 - 2
src/views/doctor/profile/index.vue

@@ -5,7 +5,7 @@
     <el-card > <!-- 调整卡片样式 -->
         <el-tabs v-model="activeTab">
             <el-tab-pane label="基本资料" name="doctorInfo">
-              <doctorInfo :doctor="doctor" :hospital="hospital" :department="department" />
+              <doctorInfo ref="doctorInfoRef"/>
             </el-tab-pane>
             <el-tab-pane label="修改密码" name="resetPwd">
               <resetPwd :doctor="doctor" />
@@ -40,7 +40,7 @@ export default {
       doctor: {},
       hospital:{},
       department:{},
-      
+
       // 表单校验
       rules: {
       }
@@ -55,6 +55,9 @@ export default {
         this.doctor = response.doctor;
         this.hospital = response.hospital;
         this.department = response.department;
+        this.$nextTick(()=>{
+          this.$refs.doctorInfoRef.loadData(response);
+        })
       });
     },
   }