certification.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. <template>
  2. <view class="container">
  3. <scroll-view class="content" scroll-y>
  4. <!-- 驳回意见提示 -->
  5. <view class="rejection-banner" v-if="rejectionInfo">
  6. <view class="rejection-icon">✕</view>
  7. <view class="rejection-text">驳回意见: {{ rejectionInfo }}</view>
  8. </view>
  9. <!-- 基本信息 -->
  10. <view class="form-section">
  11. <view class="section-header">
  12. <view class="section-indicator"></view>
  13. <text class="section-title">基本信息</text>
  14. </view>
  15. <view class="form-item">
  16. <view class="form-label">
  17. <text class="required">*</text>
  18. <text>姓名</text>
  19. </view>
  20. <input
  21. class="form-input"
  22. v-model="formData.doctorName"
  23. placeholder="请输入姓名"
  24. placeholder-class="placeholder"
  25. />
  26. </view>
  27. <view class="form-item">
  28. <view class="form-label">
  29. <text class="required">*</text>
  30. <text>身份证号</text>
  31. </view>
  32. <input
  33. class="form-input"
  34. v-model="formData.idCard"
  35. placeholder="请输入身份证号"
  36. maxlength="18"
  37. placeholder-class="placeholder"
  38. />
  39. </view>
  40. <view class="form-item">
  41. <view class="form-label">
  42. <text class="required">*</text>
  43. <text>账号身份</text>
  44. </view>
  45. <radio-group @change="onAccountIdentityChange" class="radio-group">
  46. <label
  47. class="radio-item"
  48. v-for="(option, index) in accountIdentityOptions"
  49. :key="index">
  50. <radio
  51. :value="option.value"
  52. :checked="formData.accountType == option.value"
  53. color="#388BFF"
  54. />
  55. <text class="radio-text">{{ option.label }}</text>
  56. </label>
  57. </radio-group>
  58. </view>
  59. <view class="form-item">
  60. <view class="form-label">
  61. <text class="required">*</text>
  62. <text>机构</text>
  63. </view>
  64. <input
  65. class="form-input"
  66. v-model="formData.institution"
  67. placeholder="请输入机构名称"
  68. placeholder-class="placeholder"
  69. />
  70. </view>
  71. <view class="form-item">
  72. <view class="form-label">
  73. <text class="required">*</text>
  74. <text>科室</text>
  75. </view>
  76. <input
  77. class="form-input"
  78. v-model="formData.department"
  79. placeholder="请输入科室"
  80. placeholder-class="placeholder"
  81. />
  82. </view>
  83. <view class="form-item">
  84. <view class="form-label">
  85. <text class="required">*</text>
  86. <text>职称</text>
  87. </view>
  88. <input
  89. class="form-input"
  90. v-model="formData.jobTitle"
  91. placeholder="请输入职称"
  92. placeholder-class="placeholder"
  93. />
  94. </view>
  95. </view>
  96. <!-- 身份证明 -->
  97. <view class="form-section">
  98. <view class="section-header">
  99. <view class="section-indicator"></view>
  100. <text class="section-title">身份证明</text>
  101. <view class="section-subtitle">以下资质任意选填其中一个</view>
  102. </view>
  103. <!-- 医师职业证 -->
  104. <view class="certificate-item">
  105. <view class="certificate-header">
  106. <view class="x-f">
  107. <view class="certificate-title">医师职业证</view>
  108. <view class="certificate-tip">-至少需上传编码页和执业点页</view>
  109. </view>
  110. <view class="example-btn" @click="goToPracticeExample">
  111. <image class="w28 h28" src="@/static/image/icon_example.png" mode=""></image>
  112. <text>示例</text>
  113. </view>
  114. </view>
  115. <view class="upload-grid">
  116. <view class="upload-item" v-for="(image, index) in formData.practiceCertificate" :key="index">
  117. <image class="uploaded-image" :src="image" mode="aspectFill" @click="previewImage(image, formData.practiceCertificate)"></image>
  118. <view class="delete-btn" @click="removePracticeImage(index)">×</view>
  119. </view>
  120. <view class="upload-item upload-placeholder" @click="choosePracticeImage" v-if="formData.practiceCertificate.length < 2">
  121. <image class="bg" src="@/static/image/img_idcard_Front.png" mode=""></image>
  122. <view class="img-btn">
  123. <image class="w56 h56" src="@/static/image/icon_uplodeidcard.png" mode=""></image>
  124. <text class="upload-text">点击上传</text>
  125. </view>
  126. </view>
  127. </view>
  128. </view>
  129. <!-- 医师职称证/工牌 -->
  130. <view class="certificate-item">
  131. <view class="certificate-header">
  132. <view class="certificate-title">医师职称证/工牌</view>
  133. <view class="example-btn" @click="goToTitleExample">
  134. <image class="w28 h28" src="@/static/image/icon_example.png" mode=""></image>
  135. <text>示例</text>
  136. </view>
  137. </view>
  138. <view class="upload-grid">
  139. <view class="upload-item" v-for="(image, index) in formData.titleCertificate" :key="index">
  140. <image class="uploaded-image" :src="image" mode="aspectFill" @click="previewImage(image, formData.titleCertificate)"></image>
  141. <view class="delete-btn" @click="removeTitleImage(index)">×</view>
  142. </view>
  143. <view class="upload-item upload-placeholder" @click="chooseTitleImage">
  144. <image class="bg" src="@/static/image/img_idcard_Front.png" mode=""></image>
  145. <view class="img-btn">
  146. <image class="w56 h56" src="@/static/image/icon_uplodeidcard.png" mode=""></image>
  147. <text class="upload-text">点击上传</text>
  148. </view>
  149. </view>
  150. </view>
  151. </view>
  152. </view>
  153. <!-- 银行卡信息 -->
  154. <view class="form-section">
  155. <view class="section-header">
  156. <view class="section-indicator"></view>
  157. <text class="section-title">银行卡信息</text>
  158. </view>
  159. <view class="form-item">
  160. <view class="form-label">
  161. <text class="required">*</text>
  162. <text>开户行</text>
  163. </view>
  164. <picker style="flex:1" mode="selector" :range="bankList" range-key="name" @change="onBankChange">
  165. <view class="form-input picker-input x-bc" :class="{ placeholder: !formData.bankName}">
  166. {{ formData.bankName|| '请选择开户行' }}
  167. <image class="w36 h36" src="@/static/image/icon_my_more.png" mode=""></image>
  168. </view>
  169. </picker>
  170. </view>
  171. <view class="form-item">
  172. <view class="form-label">
  173. <text class="required">*</text>
  174. <text>支行名称</text>
  175. </view>
  176. <input
  177. class="form-input"
  178. v-model="formData.bankBranch"
  179. placeholder="请输入支行名称"
  180. />
  181. </view>
  182. <view class="form-item">
  183. <view class="form-label">
  184. <text class="required">*</text>
  185. <text>银行卡号</text>
  186. </view>
  187. <input
  188. class="form-input"
  189. v-model="formData.bankCardNo"
  190. placeholder="请输入银行卡号"
  191. type="number"
  192. />
  193. </view>
  194. </view>
  195. </scroll-view>
  196. <!-- 底部操作栏 -->
  197. <view class="bottom-bar">
  198. <view class="action-buttons">
  199. <view class="btn btn-cancel" @click="handleCancel">暂不认证</view>
  200. <view class="btn btn-submit" @click="handleSubmit">提交认证</view>
  201. </view>
  202. <view class="agreement-checkbox x-c">
  203. <checkbox-group @change="onAgreementChange">
  204. <label class="checkbox-label">
  205. <checkbox value="agree" :checked="agreed" color="#388BFF" />
  206. <text class="agreement-text">
  207. 我已阅读并同意
  208. <text class="link-text" @click.stop="goToUserAgreement">《用户协议》</text>
  209. <text class="link-text" @click.stop="goToInformedConsent">《知情同意书》</text>
  210. </text>
  211. </label>
  212. </checkbox-group>
  213. </view>
  214. </view>
  215. </view>
  216. </template>
  217. <script>
  218. import {
  219. submitCertification,
  220. getCertificationInfo,
  221. getBankList,
  222. getCertificationStatus
  223. } from '@/api/certification'
  224. import { uploadOSS } from '@/api/common'
  225. export default {
  226. data() {
  227. return {
  228. rejectionInfo: '', // 驳回意见
  229. agreed: false,
  230. certificationStatus: null, // 认证状态
  231. formData: {
  232. doctorName: '', // 讲者姓名
  233. idCard: '', // 身份证号
  234. accountIdentity: '', // 账号身份(用于转换为 accountType)
  235. accountType: 1, // 账户身份: 1-医生, 2-药剂师
  236. institution: '', // 机构名称
  237. institutionId: '', // 机构ID(用于获取 companyId)
  238. companyId: '', // 公司ID
  239. companyName: '', // 公司名称
  240. department: '', // 科室
  241. jobTitle: '', // 职称
  242. licenseImage: '', // 执业证图片URL(多个图片用逗号分隔)
  243. titleCertImage: '', // 职称证/工牌图片URL(多个图片用逗号分隔)
  244. bankName: '', // 开户银行
  245. bankBranch: '', // 支行信息
  246. bankCardNo: '', // 银行卡号
  247. // 本地图片路径(用于上传)
  248. practiceCertificate: [], // 医师职业证图片数组(本地路径)
  249. titleCertificate: [] // 医师职称证/工牌图片数组(本地路径)
  250. },
  251. institutionList: [],
  252. departmentList: [],
  253. titleList: [],
  254. bankList: [
  255. { name: '中国工商银行', id: 1 },
  256. { name: '中国建设银行', id: 2 },
  257. { name: '中国银行', id: 3 },
  258. { name: '中国农业银行', id: 4 }
  259. ],
  260. selectedInstitution: null, // 选中的机构对象
  261. selectedBank: null, // 选中的银行对象
  262. accountIdentityOptions: [
  263. { label: '医生', value: 1 },
  264. { label: '药剂师', value: 2 }
  265. ]
  266. }
  267. },
  268. onLoad(options) {
  269. var user = JSON.parse(uni.getStorageSync('userInfo'))
  270. this.formData.companyId=user.companyId
  271. if (options.rejectionInfo) {
  272. this.rejectionInfo = decodeURIComponent(options.rejectionInfo)
  273. }
  274. //this.loadData()
  275. },
  276. methods: {
  277. async loadData() {
  278. try {
  279. uni.showLoading({ title: '加载中...' })
  280. // 并行加载所有数据
  281. const [infoRes, statusRes, bankRes] = await Promise.all([
  282. getCertificationInfo().catch(() => ({ code: 0 })),
  283. getCertificationStatus().catch(() => ({ code: 0 })),
  284. // getBankList().catch(() => ({ code: 0, data: [] }))
  285. ])
  286. // 加载认证信息(如果已提交过)
  287. if (infoRes.code === 200 && infoRes.data) {
  288. const data = infoRes.data
  289. // 映射接口返回的字段到表单字段
  290. this.formData = {
  291. ...this.formData,
  292. doctorName: data.doctorName || data.name || '',
  293. idCard: data.idCard || data.idNumber || '',
  294. accountType: data.accountType || '',
  295. accountIdentity: data.accountType === 1 ? '医生' : (data.accountType === 2 ? '药剂师' : ''),
  296. institution: data.institution || '',
  297. companyId: data.companyId || '',
  298. companyName: data.companyName || '',
  299. department: data.department || '',
  300. jobTitle: data.jobTitle || data.title || '',
  301. bankName: data.bankName || data.bank || '',
  302. bankBranch: data.bankBranch || data.branchName || '',
  303. bankCardNo: data.bankCardNo || data.bankCardNumber || '',
  304. // 处理图片URL,转换为数组
  305. licenseImage: data.licenseImage || '',
  306. titleCertImage: data.titleCertImage || '',
  307. practiceCertificate: data.licenseImage ? data.licenseImage.split(',').filter(Boolean) : [],
  308. titleCertificate: data.titleCertImage ? data.titleCertImage.split(',').filter(Boolean) : []
  309. }
  310. // 设置账号身份
  311. if (data.accountType) {
  312. const selected = this.accountIdentityOptions.find(opt => opt.value === data.accountType)
  313. if (selected) {
  314. this.formData.accountIdentity = selected.label
  315. this.formData.accountType = selected.value
  316. }
  317. }
  318. // 如果有id(编辑时),保存id
  319. if (data.id) {
  320. this.formData.id = data.id
  321. }
  322. if (data.rejectionInfo) {
  323. this.rejectionInfo = data.rejectionInfo
  324. }
  325. }
  326. // 加载认证状态
  327. if (statusRes.code === 200 && statusRes.data) {
  328. this.certificationStatus = statusRes.data
  329. }
  330. // // 加载选项数据
  331. // if (bankRes.code === 200 && bankRes.data) {
  332. // this.bankList = bankRes.data
  333. // } else {
  334. // this.bankList = []
  335. // }
  336. uni.hideLoading()
  337. } catch (e) {
  338. uni.hideLoading()
  339. console.error('加载数据失败', e)
  340. }
  341. },
  342. onBankChange(e) {
  343. const index = e.detail.value
  344. this.formData.bankName = this.bankList[index].name
  345. //this.formData.bankCardNo = this.bankList[index].id
  346. this.formData.bankBranch = '' // 清空支行选择
  347. },
  348. onAccountIdentityChange(e) {
  349. const value = parseInt(e.detail.value)
  350. const selected = this.accountIdentityOptions.find(opt => opt.value === value)
  351. if (selected) {
  352. this.formData.accountIdentity = selected.label
  353. this.formData.accountType = selected.value
  354. }
  355. },
  356. onAgreementChange(e) {
  357. this.agreed = e.detail.value.includes('agree')
  358. },
  359. choosePracticeImage() {
  360. uni.chooseImage({
  361. count: 2 - this.formData.practiceCertificate.length,
  362. sizeType: ['compressed'],
  363. sourceType: ['album', 'camera'],
  364. success: (res) => {
  365. // 立即上传图片
  366. uni.showLoading({ title: '上传中...' })
  367. this.uploadImages(res.tempFilePaths, (urls) => {
  368. uni.hideLoading()
  369. // 保存上传后的URL
  370. this.formData.practiceCertificate = [...this.formData.practiceCertificate, ...urls]
  371. uni.showToast({ icon: 'success', title: '上传成功' })
  372. }, (error) => {
  373. uni.hideLoading()
  374. uni.showToast({ icon: 'none', title: error || '上传失败' })
  375. })
  376. }
  377. })
  378. },
  379. removePracticeImage(index) {
  380. this.formData.practiceCertificate.splice(index, 1)
  381. },
  382. async chooseTitleImage() {
  383. uni.chooseImage({
  384. count: 9 - this.formData.titleCertificate.length,
  385. sizeType: ['compressed'],
  386. sourceType: ['album', 'camera'],
  387. success: (res) => {
  388. // 立即上传图片
  389. uni.showLoading({ title: '上传中...' })
  390. this.uploadImages(res.tempFilePaths, (urls) => {
  391. uni.hideLoading()
  392. // 保存上传后的URL
  393. this.formData.titleCertificate = [...this.formData.titleCertificate, ...urls]
  394. uni.showToast({ icon: 'success', title: '上传成功' })
  395. }, (error) => {
  396. uni.hideLoading()
  397. uni.showToast({ icon: 'none', title: error || '上传失败' })
  398. })
  399. }
  400. })
  401. },
  402. // 上传多张图片(不使用 Promise)
  403. uploadImages(filePaths, successCallback, failCallback) {
  404. const requestPath = uni.getStorageSync('requestPath') || 'http://t9794bec.natappfree.cc'
  405. const urls = []
  406. let completed = 0
  407. let hasError = false
  408. if (filePaths.length === 0) {
  409. successCallback([])
  410. return
  411. }
  412. filePaths.forEach((filePath, index) => {
  413. uni.uploadFile({
  414. url: `${requestPath}/app/common/uploadOSS`,
  415. filePath: filePath,
  416. name: 'file',
  417. success: (uploadRes) => {
  418. if (hasError) return
  419. try {
  420. const result = typeof uploadRes.data === 'string' ? JSON.parse(uploadRes.data) : uploadRes.data
  421. if (result.code == 200) {
  422. urls[index] = result.url || result.data?.url || ''
  423. } else {
  424. hasError = true
  425. failCallback(result.msg || '上传失败')
  426. return
  427. }
  428. } catch (e) {
  429. hasError = true
  430. failCallback('解析上传结果失败')
  431. return
  432. }
  433. completed++
  434. if (completed === filePaths.length) {
  435. successCallback(urls.filter(Boolean))
  436. }
  437. },
  438. fail: (err) => {
  439. if (hasError) return
  440. hasError = true
  441. failCallback('上传失败')
  442. }
  443. })
  444. })
  445. },
  446. removeTitleImage(index) {
  447. this.formData.titleCertificate.splice(index, 1)
  448. },
  449. previewImage(current, urls) {
  450. uni.previewImage({
  451. current: current,
  452. urls: urls
  453. })
  454. },
  455. goToPracticeExample() {
  456. uni.navigateTo({
  457. url: '/pages_user/practiceCertificateExample'
  458. })
  459. },
  460. goToTitleExample() {
  461. uni.navigateTo({
  462. url: '/pages_user/certificationExample'
  463. })
  464. },
  465. goToUserAgreement() {
  466. uni.navigateTo({
  467. url: '/pages_user/userAgreement'
  468. })
  469. },
  470. goToInformedConsent() {
  471. uni.navigateTo({
  472. url: '/pages_user/informedConsent'
  473. })
  474. },
  475. handleCancel() {
  476. uni.navigateBack()
  477. },
  478. async handleSubmit() {
  479. // 表单验证
  480. if (!this.formData.doctorName && !this.formData.name) {
  481. uni.showToast({
  482. icon: 'none',
  483. title: '请输入姓名'
  484. })
  485. return
  486. }
  487. if (!this.formData.idCard && !this.formData.idNumber) {
  488. uni.showToast({
  489. icon: 'none',
  490. title: '请输入身份证号'
  491. })
  492. return
  493. }
  494. if (!this.formData.accountType) {
  495. uni.showToast({
  496. icon: 'none',
  497. title: '请选择账号身份'
  498. })
  499. return
  500. }
  501. if (!this.formData.institution) {
  502. uni.showToast({
  503. icon: 'none',
  504. title: '请输入机构名称'
  505. })
  506. return
  507. }
  508. if (!this.formData.department) {
  509. uni.showToast({
  510. icon: 'none',
  511. title: '请输入科室'
  512. })
  513. return
  514. }
  515. if (!this.formData.jobTitle && !this.formData.title) {
  516. uni.showToast({
  517. icon: 'none',
  518. title: '请输入职称'
  519. })
  520. return
  521. }
  522. // 至少上传一种证件
  523. if (this.formData.practiceCertificate.length === 0 && this.formData.titleCertificate.length === 0) {
  524. uni.showToast({
  525. icon: 'none',
  526. title: '请至少上传一种身份证明'
  527. })
  528. return
  529. }
  530. // 医师职业证至少上传2张
  531. if (this.formData.practiceCertificate.length > 0 && this.formData.practiceCertificate.length < 2) {
  532. uni.showToast({
  533. icon: 'none',
  534. title: '医师职业证至少需上传编码页和执业点页'
  535. })
  536. return
  537. }
  538. if (!this.formData.bankName && !this.formData.bank) {
  539. uni.showToast({
  540. icon: 'none',
  541. title: '请选择开户行'
  542. })
  543. return
  544. }
  545. if (!this.formData.bankBranch && !this.formData.branchName) {
  546. uni.showToast({
  547. icon: 'none',
  548. title: '请输入支行名称'
  549. })
  550. return
  551. }
  552. if (!this.formData.bankCardNo && !this.formData.bankCardNumber) {
  553. uni.showToast({
  554. icon: 'none',
  555. title: '请输入银行卡号'
  556. })
  557. return
  558. }
  559. if (!this.agreed) {
  560. uni.showToast({
  561. icon: 'none',
  562. title: '请阅读并同意用户协议和知情同意书'
  563. })
  564. return
  565. }
  566. try {
  567. uni.showLoading({ title: '提交中...' })
  568. // 获取图片URL(选择时已上传,直接使用)
  569. const licenseImageUrls = this.formData.practiceCertificate.filter(url => url && (url.startsWith('http://') || url.startsWith('https://')))
  570. const titleCertImageUrls = this.formData.titleCertificate.filter(url => url && (url.startsWith('http://') || url.startsWith('https://')))
  571. // 构建提交数据,按照接口字段要求
  572. const submitData = {
  573. accountType: this.formData.accountType, // 账户身份: 1-医生, 2-药剂师
  574. bankBranch: this.formData.bankBranch || this.formData.branchName, // 支行信息
  575. bankCardNo: this.formData.bankCardNo || this.formData.bankCardNumber, // 银行卡号
  576. bankName: this.formData.bankName || this.formData.bank, // 开户银行
  577. companyId: this.formData.companyId || '', // 公司ID
  578. companyName: this.formData.companyName || this.formData.institution, // 公司名称
  579. department: this.formData.department, // 科室
  580. doctorName: this.formData.doctorName || this.formData.name, // 讲者姓名
  581. idCard: this.formData.idCard || this.formData.idNumber, // 身份证号
  582. institution: this.formData.institution, // 机构名称
  583. jobTitle: this.formData.jobTitle || this.formData.title, // 职称
  584. licenseImage: licenseImageUrls.join(','), // 执业证图片URL(多个用逗号分隔)
  585. titleCertImage: titleCertImageUrls.join(',') // 职称证/工牌图片URL(多个用逗号分隔)
  586. }
  587. // 如果有id(编辑时),添加id字段
  588. if (this.formData.id) {
  589. submitData.id = this.formData.id
  590. }
  591. const res = await submitCertification(submitData)
  592. uni.hideLoading()
  593. if (res.code === 200) {
  594. uni.showToast({
  595. icon: 'success',
  596. title: '提交成功'
  597. })
  598. setTimeout(() => {
  599. uni.navigateBack()
  600. }, 1500)
  601. } else {
  602. uni.showToast({
  603. icon: 'none',
  604. title: res.msg || '提交失败'
  605. })
  606. }
  607. } catch (e) {
  608. uni.hideLoading()
  609. console.error('提交认证失败', e)
  610. uni.showToast({
  611. icon: 'none',
  612. title: e.message || '提交失败'
  613. })
  614. }
  615. }
  616. }
  617. }
  618. </script>
  619. <style lang="scss" scoped>
  620. .container {
  621. min-height: 100vh;
  622. background: #f5f5f5;
  623. display: flex;
  624. flex-direction: column;
  625. }
  626. .content {
  627. flex: 1;
  628. padding-bottom: 200rpx;
  629. box-sizing: border-box;
  630. }
  631. .rejection-banner {
  632. display: flex;
  633. align-items: center;
  634. padding: 24rpx;
  635. background: #FF5030;
  636. color: #fff;
  637. margin: 24rpx;
  638. border-radius: 8rpx;
  639. .rejection-icon {
  640. width: 40rpx;
  641. height: 40rpx;
  642. border-radius: 50%;
  643. background: rgba(255, 255, 255, 0.3);
  644. display: flex;
  645. align-items: center;
  646. justify-content: center;
  647. font-size: 24rpx;
  648. margin-right: 16rpx;
  649. }
  650. .rejection-text {
  651. flex: 1;
  652. font-size: 28rpx;
  653. line-height: 1.5;
  654. }
  655. }
  656. .form-section {
  657. background: #fff;
  658. margin: 20rpx;
  659. border-radius: 16rpx;
  660. padding: 32rpx;
  661. .section-header {
  662. display: flex;
  663. align-items: center;
  664. margin-bottom: 32rpx;
  665. .section-indicator {
  666. width: 6rpx;
  667. height: 32rpx;
  668. background: #388BFF;
  669. border-radius: 3rpx;
  670. margin-right: 16rpx;
  671. }
  672. .section-title {
  673. font-size: 32rpx;
  674. font-weight: bold;
  675. color: #333;
  676. }
  677. }
  678. .section-subtitle {
  679. font-size: 24rpx;
  680. color: #999;
  681. //margin-bottom: 24rpx;
  682. margin-left: 22rpx;
  683. }
  684. .form-item {
  685. margin-bottom: 32rpx;
  686. display: flex;
  687. align-items: center;
  688. border-bottom: 1px solid #EBEDF0;
  689. &:last-child {
  690. border-bottom: 0;
  691. margin-bottom: 0;
  692. }
  693. .form-label {
  694. display: flex;
  695. align-items: center;
  696. font-size: 28rpx;
  697. color: #333;
  698. // margin-bottom: 16rpx;
  699. width: 160rpx;
  700. .required {
  701. color: #FF5030;
  702. margin-right: 4rpx;
  703. }
  704. }
  705. .form-input {
  706. // width: 100%;
  707. flex:1;
  708. height: 80rpx;
  709. font-size: 28rpx;
  710. }
  711. .radio-group {
  712. flex: 1;
  713. display: flex;
  714. align-items: center;
  715. gap: 48rpx;
  716. height: 80rpx;
  717. .radio-item {
  718. display: flex;
  719. align-items: center;
  720. gap: 8rpx;
  721. .radio-text {
  722. font-size: 28rpx;
  723. color: #333;
  724. }
  725. }
  726. // padding: 0 24rpx;
  727. font-size: 28rpx;
  728. color: #333;
  729. &.placeholder {
  730. color: #C8C9CC;
  731. }
  732. &.picker-input {
  733. display: flex;
  734. align-items: center;
  735. justify-content: space-between;
  736. .arrow-right {
  737. font-size: 32rpx;
  738. color: #999;
  739. }
  740. }
  741. }
  742. }
  743. .certificate-item {
  744. padding-bottom: 32rpx;
  745. margin-bottom: 32rpx;
  746. border-bottom: 2rpx solid #F5F5F5;
  747. &:last-child {
  748. margin-bottom: 0;
  749. border-bottom: 0;
  750. }
  751. .certificate-header {
  752. display: flex;
  753. align-items: center;
  754. justify-content: space-between;
  755. margin-bottom: 24rpx;
  756. .certificate-title {
  757. font-size: 28rpx;
  758. color: #333;
  759. font-weight: 500;
  760. }
  761. .example-btn {
  762. display: flex;
  763. align-items: center;
  764. gap: 8rpx;
  765. font-size: 24rpx;
  766. color: #388BFF;
  767. .example-icon {
  768. width: 32rpx;
  769. height: 32rpx;
  770. border-radius: 50%;
  771. background: #E6F7FF;
  772. display: flex;
  773. align-items: center;
  774. justify-content: center;
  775. font-size: 20rpx;
  776. color: #388BFF;
  777. }
  778. }
  779. }
  780. .certificate-tip {
  781. font-size: 24rpx;
  782. color: #999;
  783. // margin-bottom: 16rpx;
  784. }
  785. .upload-grid {
  786. display: flex;
  787. gap: 16rpx;
  788. flex-wrap: wrap;
  789. .upload-item {
  790. width: 310rpx;
  791. height: 176rpx;
  792. border-radius: 8rpx;
  793. overflow: hidden;
  794. position: relative;
  795. .uploaded-image {
  796. width: 100%;
  797. height: 100%;
  798. }
  799. .bg{
  800. width: 100%;
  801. height: 100%;
  802. position: absolute;
  803. top: 0;
  804. left: 0;
  805. }
  806. .delete-btn {
  807. position: absolute;
  808. top: 0;
  809. right: 0;
  810. width: 40rpx;
  811. height: 40rpx;
  812. line-height: 40rpx;
  813. background: rgba(0, 0, 0, 0.5);
  814. border-radius: 50%;
  815. display: flex;
  816. align-items: center;
  817. justify-content: center;
  818. font-size: 32rpx;
  819. color: #fff;
  820. }
  821. &.upload-placeholder {
  822. background: #f5f5f5;
  823. display: flex;
  824. flex-direction: column;
  825. align-items: center;
  826. justify-content: center;
  827. // border: 2rpx dashed #ddd;
  828. .img-btn{
  829. z-index: 1;
  830. display: flex;
  831. flex-direction: column;
  832. align-items: center;
  833. justify-content: center;
  834. }
  835. .camera-icon {
  836. font-size: 60rpx;
  837. margin-bottom: 8rpx;
  838. }
  839. .upload-text {
  840. font-size: 24rpx;
  841. color: #388BFF;
  842. }
  843. }
  844. }
  845. }
  846. }
  847. }
  848. .bottom-bar {
  849. position: fixed;
  850. bottom: 0;
  851. left: 0;
  852. right: 0;
  853. background: #fff;
  854. padding: 24rpx;
  855. // border-top: 1rpx solid #f0f0f0;
  856. z-index: 100;
  857. .agreement-checkbox {
  858. margin-bottom: 24rpx;
  859. margin-top: 20rpx;
  860. .checkbox-label {
  861. display: flex;
  862. align-items: flex-start;
  863. font-size: 24rpx;
  864. color: #666;
  865. .agreement-text {
  866. margin-left: 8rpx;
  867. line-height: 1.5;
  868. .link-text {
  869. color: #388BFF;
  870. }
  871. }
  872. }
  873. }
  874. .action-buttons {
  875. display: flex;
  876. gap: 24rpx;
  877. .btn {
  878. flex: 1;
  879. height: 88rpx;
  880. display: flex;
  881. align-items: center;
  882. justify-content: center;
  883. border-radius: 8rpx;
  884. font-size: 32rpx;
  885. font-weight: 500;
  886. border-radius: 200rpx 200rpx 200rpx 200rpx;
  887. &.btn-cancel {
  888. background: #fff;
  889. border: 2rpx solid #388BFF;
  890. color: #388BFF;
  891. }
  892. &.btn-submit {
  893. background: #388BFF;
  894. color: #fff;
  895. }
  896. }
  897. }
  898. }
  899. </style>