lex 2 年之前
父節點
當前提交
6726552e2d

+ 65 - 0
src/components/o-upload/index.module.less

@@ -0,0 +1,65 @@
+.uploader-section {
+  margin: 10px 0;
+  height: 145px;
+  border: 1px dashed #ccc;
+  border-radius: 10px;
+  box-sizing: border-box;
+  position: relative;
+  .img-close {
+    position: absolute;
+    top: 8px;
+    right: 10px;
+    z-index: 99;
+    font-size: 16px;
+    background-color: #333;
+    color: #fff;
+    width: 22px;
+    height: 22px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    border-radius: 50%;
+  }
+  .col-uploader {
+    width: 100%;
+    height: 100%;
+    align-items: center;
+    display: flex;
+    justify-content: center;
+  }
+  :global {
+    .van-uploader {
+      width: 100%;
+      height: 100%;
+      align-items: center;
+      display: flex;
+      justify-content: center;
+    }
+    .van-uploader__wrapper, .van-uploader__input-wrapper {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      width: inherit;
+      height: inherit;
+    }
+  }
+  .uploader {
+    // width: 300px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    .uploaderText {
+      font-size: 14px;
+      color: #999999;
+      margin-top: 8px;
+    }
+  }
+
+  .uploadImg {
+    width: 100%;
+    height: 100%;
+    // border-radius: 10px;
+    overflow: hidden;
+  }
+}

+ 222 - 0
src/components/o-upload/index.tsx

@@ -0,0 +1,222 @@
+import { closeToast, Icon, Image, showToast, Toast, Uploader } from 'vant'
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+import ColCropper from '../o-cropper'
+import { useCustomFieldValue } from '@vant/use'
+import { postMessage } from '@/helpers/native-message'
+import umiRequest from 'umi-request'
+import iconUploader from '@common/images/icon_uploader.png'
+import request from '@/helpers/request'
+import { getOssUploadUrl, state } from '@/state'
+
+export default defineComponent({
+  name: 'col-upload',
+  props: {
+    modelValue: String,
+    tips: {
+      type: String,
+      default: '点击上传'
+    },
+    deletable: {
+      type: Boolean,
+      default: true
+    },
+    native: {
+      // 是否原生上传
+      type: Boolean,
+      default: false
+    },
+    cropper: {
+      // 是否进行裁切
+      type: Boolean,
+      default: false
+    },
+    options: {
+      // 裁切需要参数
+      type: Object,
+      default: {}
+    },
+    uploadSize: {
+      // 上传图片大小
+      type: Number,
+      default: 5
+    },
+    onUploadChange: {
+      type: Function,
+      default: (url: string) => {}
+    },
+    bucket: {
+      type: String,
+      default: 'daya'
+    }
+  },
+  methods: {
+    nativeUpload() {
+      postMessage(
+        {
+          api: 'chooseFile',
+          content: { type: 'img', max: 1, bucket: this.bucket }
+        },
+        (res: any) => {
+          console.log(res, 'fileUrl')
+          this.$emit('update:modelValue', res.fileUrl)
+        }
+      )
+    },
+    beforeRead(file: any) {
+      console.log(file, 'beforeRead')
+      const isLt2M = file.size / 1024 / 1024 < this.uploadSize
+      if (!isLt2M) {
+        showToast(`上传文件大小不能超过 ${this.uploadSize}MB`)
+        return false
+      }
+      return true
+    },
+    beforeDelete(file: any, detail: { index: any }) {
+      // this.dataModel.splice(detail.index, 1)
+      return true
+    },
+    async afterRead(file: any, detail: any) {
+      try {
+        file.status = 'uploading'
+        file.message = '上传中...'
+        await this.uploadFile(file.file)
+      } catch (error) {
+        //
+        console.log(error, '2323')
+
+        closeToast()
+      }
+    },
+    onClose(e: any) {
+      this.$emit('update:modelValue', null)
+      this.onUploadChange()
+      e.stopPropagation()
+    },
+    async getFile(file: any) {
+      try {
+        await this.uploadFile(file)
+      } catch {
+        //
+      }
+    },
+    async uploadFile(file: any) {
+      // 上传文件
+      try {
+        // 获取签名
+        const signUrl = state.platformApi + '/open/getUploadSign'
+        const tempName = file.name || ''
+        const fileName = tempName && tempName.replace(/ /gi, '_')
+        const key = new Date().getTime() + fileName
+        console.log(file)
+
+        const res = await request.post(signUrl, {
+          data: {
+            filename: fileName,
+            bucketName: this.bucket,
+            postData: {
+              filename: fileName,
+              acl: 'public-read',
+              key: key,
+              unknowValueField: []
+            }
+          }
+        })
+        Toast.loading({
+          message: '加载中...',
+          forbidClick: true,
+          loadingType: 'spinner',
+          duration: 0
+        })
+        const obj = {
+          policy: res.data.policy,
+          signature: res.data.signature,
+          key: key,
+          KSSAccessKeyId: res.data.kssAccessKeyId,
+          acl: 'public-read',
+          name: fileName
+        }
+        const formData = new FormData()
+        for (const key in obj) {
+          formData.append(key, obj[key])
+        }
+        formData.append('file', file, fileName)
+        await umiRequest(getOssUploadUrl(this.bucket), {
+          method: 'POST',
+          data: formData
+        })
+        console.log(getOssUploadUrl(this.bucket) + key)
+        const uploadUrl = getOssUploadUrl(this.bucket) + key
+        Toast.clear()
+        this.$emit('update:modelValue', uploadUrl)
+        this.onUploadChange(uploadUrl)
+      } catch (error) {
+        console.log(error, 'uploadFile')
+      }
+    }
+  },
+  render() {
+    useCustomFieldValue(() => this.modelValue)
+    return (
+      <div class={styles['uploader-section']}>
+        {this.modelValue && this.deletable ? (
+          <Icon name="cross" onClick={this.onClose} class={styles['img-close']} />
+        ) : null}
+        {this.cropper && !this.native ? (
+          <div class={styles['col-uploader']}>
+            {this.modelValue ? (
+              <Image fit="cover" position="center" class={styles.uploadImg} src={this.modelValue} />
+            ) : (
+              <div class={styles.uploader}>
+                <Icon name={iconUploader} size="32" />
+                <p class={styles.uploaderText}>{this.tips}</p>
+              </div>
+            )}
+            <ColCropper option={this.options} getFile={this.getFile} />
+          </div>
+        ) : this.native ? (
+          <div
+            style={{
+              display: 'flex',
+              alignItems: 'center',
+              justifyContent: 'center',
+              height: '100%'
+            }}
+            onClick={this.nativeUpload}
+          >
+            {this.modelValue ? (
+              <Image fit="cover" position="center" class={styles.uploadImg} src={this.modelValue} />
+            ) : (
+              <div class={styles.uploader}>
+                <Icon name={iconUploader} size="32" />
+                <p class={styles.uploaderText}>{this.tips}</p>
+              </div>
+            )}
+          </div>
+        ) : (
+          <Uploader
+            afterRead={this.afterRead}
+            beforeRead={this.beforeRead}
+            beforeDelete={this.beforeDelete}
+            v-slots={{
+              default: () =>
+                this.modelValue ? (
+                  <Image
+                    fit="cover"
+                    position="center"
+                    class={styles.uploadImg}
+                    src={this.modelValue}
+                  />
+                ) : (
+                  <div class={styles.uploader}>
+                    <Icon name={iconUploader} size="32" />
+                    <p class={styles.uploaderText}>{this.tips}</p>
+                  </div>
+                )
+            }}
+          />
+        )}
+      </div>
+    )
+  }
+})

+ 105 - 5
src/school/companion-teacher/companion-teacher-register.tsx

@@ -26,6 +26,7 @@ import schoolLogo from './images/school-logo.png'
 import iconClose from './images/icon-close.png'
 import topBanner1 from './images/top-banner1.png'
 import { checkPhone } from '@/helpers/validate'
+import OUpload from '@/components/o-upload'
 
 export default defineComponent({
   name: 'companion-teacher-register',
@@ -36,6 +37,7 @@ export default defineComponent({
       showPicker: false,
       showSubject: false,
       submitStatus: false,
+      showEducation: false,
       id: route.query.id,
       name: route.query.name,
       pattern: /^1(3|4|5|6|7|8|9)\d{9}$/,
@@ -51,7 +53,11 @@ export default defineComponent({
         cityCodeName: '',
         provinceCode: null,
         subjectIds: [],
-        smsValidCode: ''
+        smsValidCode: '',
+        educationBackground: '', // 学历
+        graduateSchool: null, // 毕业学校
+        idcardFrontImg: '',
+        idcardBackImg: '' // 身份证反面照
       },
       btnLoading: false,
       checkPhone: false,
@@ -133,6 +139,13 @@ export default defineComponent({
       state.showSubject = false
     }
 
+    // 选择学历
+    const onConfirmEduction = (val: any) => {
+      const selectedOptions = val.selectedOptions[0]
+      state.forms.educationBackground = selectedOptions.value
+      state.showEducation = false
+    }
+
     const onSendCode = () => {
       // 发送验证码
       if (!checkPhone(state.forms.phone as any)) {
@@ -320,6 +333,73 @@ export default defineComponent({
 
             <Field
               required
+              label="身份证照片正面"
+              v-model={state.forms.idcardFrontImg}
+              readonly
+              name="idcardFrontImg"
+              onClick={() => (state.showPicker = true)}
+              rules={[{ required: true, message: '请选择身份证照片正面', trigger: 'onChange' }]}
+              placeholder="请选择身份证照片正面"
+            >
+              {{
+                input: () => (
+                  <OUpload
+                    style={{ width: '100%' }}
+                    tips="上传身份证正面"
+                    v-model:modelValue={state.forms.idcardFrontImg}
+                  />
+                )
+              }}
+            </Field>
+            <Field
+              required
+              label="身份证照片反面"
+              v-model={state.forms.idcardFrontImg}
+              readonly
+              name="idcardFrontImg"
+              onClick={() => (state.showPicker = true)}
+              rules={[{ required: true, message: '请选择身份证照片反面', trigger: 'onChange' }]}
+              placeholder="请选择身份证照片反面"
+            >
+              {{
+                input: () => (
+                  <OUpload
+                    style={{ width: '100%' }}
+                    tips="上传身份证正面"
+                    v-model:modelValue={state.forms.idcardFrontImg}
+                  />
+                )
+              }}
+            </Field>
+
+            <Field
+              required
+              label="学历"
+              v-model={state.forms.educationBackground}
+              readonly
+              name="educationBackground"
+              onClick={() => (state.showEducation = true)}
+              rules={[{ required: true, message: '请选择学历', trigger: 'onChange' }]}
+              placeholder="请选择学历"
+            >
+              {{
+                'right-icon': () => (
+                  <Icon name="arrow" color={state.checkPhone ? '#aaa' : '#323233'} size="16"></Icon>
+                )
+              }}
+            </Field>
+
+            <Field
+              required
+              label="毕业学校"
+              v-model={state.forms.graduateSchool}
+              rules={[{ required: true, message: '请输入毕业学校' }]}
+              name="graduateSchool"
+              placeholder="请输入毕业学校"
+            ></Field>
+
+            <Field
+              required
               label="所在城市"
               v-model={state.forms.cityCodeName}
               readonly
@@ -409,7 +489,6 @@ export default defineComponent({
             完成
           </Button>
         </Form>
-
         <Popup v-model:show={state.showPicker} position="bottom" round>
           <Picker
             showToolbar
@@ -419,7 +498,6 @@ export default defineComponent({
             columnsFieldNames={{ text: 'name', value: 'code', children: 'areas' }}
           />
         </Popup>
-
         <Popup v-model:show={state.showSubject} position="bottom" round>
           <Picker
             showToolbar
@@ -428,7 +506,30 @@ export default defineComponent({
             onConfirm={onConfirmSubject}
           />
         </Popup>
-
+        <Popup v-model:show={state.showSubject} position="bottom" round>
+          <Picker
+            showToolbar
+            columns={state.columnSubject}
+            onCancel={() => (state.showSubject = false)}
+            onConfirm={onConfirmSubject}
+          />
+        </Popup>
+        {/* 学历 */}
+        {/* 学历分为专科、本科、硕士、博士、其他 */}
+        <Popup v-model:show={state.showEducation} position="bottom" round>
+          <Picker
+            showToolbar
+            columns={[
+              { text: '专科', value: '专科' },
+              { text: '本科', value: '本科' },
+              { text: '硕士', value: '硕士' },
+              { text: '博士', value: '博士' },
+              { text: '其他', value: '其他' }
+            ]}
+            onCancel={() => (state.showEducation = false)}
+            onConfirm={onConfirmEduction}
+          />
+        </Popup>
         <Popup v-model:show={state.submitStatus} round style="width: 75%" closeOnClickOverlay>
           <div class={styles.stautsS}>
             <img
@@ -455,7 +556,6 @@ export default defineComponent({
             </div>
           </div>
         </Popup>
-
         {state.imgCodeStatus ? (
           <ImgCode
             v-model:value={state.imgCodeStatus}

+ 2 - 2
vite.config.ts

@@ -12,8 +12,8 @@ function resolve(dir: string) {
 // https://vitejs.dev/config/
 // https://github.com/vitejs/vite/issues/1930 .env
 // const proxyUrl = 'https://mstutest.dayaedu.com/';
-const proxyUrl = 'http://47.98.131.38:8989/'
-// const proxyUrl = 'http://192.168.3.26:8989/'
+// const proxyUrl = 'http://47.98.131.38:8989/'
+const proxyUrl = 'http://192.168.3.26:8989/'
 export default defineConfig({
   base: './',
   plugins: [