certification.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  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" v-if="formData.titleCertificate.length < 2">
  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. <input
  165. class="form-input"
  166. v-model="formData.bankName"
  167. placeholder="请输入开户行"
  168. placeholder-class="text-placeholder"
  169. />
  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. selectedInstitution: null, // 选中的机构对象
  255. selectedBank: null, // 选中的银行对象
  256. accountIdentityOptions: [
  257. { label: '医生', value: 1 },
  258. { label: '药剂师', value: 2 }
  259. ]
  260. }
  261. },
  262. onLoad(options) {
  263. var user = JSON.parse(uni.getStorageSync('userInfo'))
  264. this.formData.companyId=user.companyId
  265. if (options.rejectionInfo) {
  266. this.rejectionInfo = decodeURIComponent(options.rejectionInfo)
  267. }
  268. //this.loadData()
  269. },
  270. methods: {
  271. async loadData() {
  272. try {
  273. uni.showLoading({ title: '加载中...' })
  274. // 并行加载所有数据
  275. const [infoRes, statusRes, bankRes] = await Promise.all([
  276. getCertificationInfo().catch(() => ({ code: 0 })),
  277. getCertificationStatus().catch(() => ({ code: 0 })),
  278. // getBankList().catch(() => ({ code: 0, data: [] }))
  279. ])
  280. // 加载认证信息(如果已提交过)
  281. if (infoRes.code === 200 && infoRes.data) {
  282. const data = infoRes.data
  283. // 映射接口返回的字段到表单字段
  284. this.formData = {
  285. ...this.formData,
  286. doctorName: data.doctorName || data.name || '',
  287. idCard: data.idCard || data.idNumber || '',
  288. accountType: data.accountType || '',
  289. accountIdentity: data.accountType === 1 ? '医生' : (data.accountType === 2 ? '药剂师' : ''),
  290. institution: data.institution || '',
  291. companyId: data.companyId || '',
  292. companyName: data.companyName || '',
  293. department: data.department || '',
  294. jobTitle: data.jobTitle || data.title || '',
  295. bankName: data.bankName || data.bank || '',
  296. bankBranch: data.bankBranch || data.branchName || '',
  297. bankCardNo: data.bankCardNo || data.bankCardNumber || '',
  298. // 处理图片URL,转换为数组
  299. licenseImage: data.licenseImage || '',
  300. titleCertImage: data.titleCertImage || '',
  301. practiceCertificate: data.licenseImage ? data.licenseImage.split(',').filter(Boolean) : [],
  302. titleCertificate: data.titleCertImage ? data.titleCertImage.split(',').filter(Boolean) : []
  303. }
  304. // 设置账号身份
  305. if (data.accountType) {
  306. const selected = this.accountIdentityOptions.find(opt => opt.value === data.accountType)
  307. if (selected) {
  308. this.formData.accountIdentity = selected.label
  309. this.formData.accountType = selected.value
  310. }
  311. }
  312. // 如果有id(编辑时),保存id
  313. if (data.id) {
  314. this.formData.id = data.id
  315. }
  316. if (data.rejectionInfo) {
  317. this.rejectionInfo = data.rejectionInfo
  318. }
  319. }
  320. // 加载认证状态
  321. if (statusRes.code === 200 && statusRes.data) {
  322. this.certificationStatus = statusRes.data
  323. }
  324. uni.hideLoading()
  325. } catch (e) {
  326. uni.hideLoading()
  327. console.error('加载数据失败', e)
  328. }
  329. },
  330. onAccountIdentityChange(e) {
  331. const value = parseInt(e.detail.value)
  332. const selected = this.accountIdentityOptions.find(opt => opt.value === value)
  333. if (selected) {
  334. this.formData.accountIdentity = selected.label
  335. this.formData.accountType = selected.value
  336. }
  337. },
  338. onAgreementChange(e) {
  339. this.agreed = e.detail.value.includes('agree')
  340. },
  341. choosePracticeImage() {
  342. uni.chooseImage({
  343. count: 2 - this.formData.practiceCertificate.length,
  344. sizeType: ['compressed'],
  345. sourceType: ['album', 'camera'],
  346. success: (res) => {
  347. // 立即上传图片
  348. uni.showLoading({ title: '上传中...' })
  349. this.uploadImages(res.tempFilePaths, (urls) => {
  350. uni.hideLoading()
  351. // 保存上传后的URL
  352. this.formData.practiceCertificate = [...this.formData.practiceCertificate, ...urls]
  353. uni.showToast({ icon: 'success', title: '上传成功' })
  354. }, (error) => {
  355. uni.hideLoading()
  356. uni.showToast({ icon: 'none', title: error || '上传失败' })
  357. })
  358. }
  359. })
  360. },
  361. removePracticeImage(index) {
  362. this.formData.practiceCertificate.splice(index, 1)
  363. },
  364. async chooseTitleImage() {
  365. uni.chooseImage({
  366. count: 9 - this.formData.titleCertificate.length,
  367. sizeType: ['compressed'],
  368. sourceType: ['album', 'camera'],
  369. success: (res) => {
  370. // 立即上传图片
  371. uni.showLoading({ title: '上传中...' })
  372. this.uploadImages(res.tempFilePaths, (urls) => {
  373. uni.hideLoading()
  374. // 保存上传后的URL
  375. this.formData.titleCertificate = [...this.formData.titleCertificate, ...urls]
  376. uni.showToast({ icon: 'success', title: '上传成功' })
  377. }, (error) => {
  378. uni.hideLoading()
  379. uni.showToast({ icon: 'none', title: error || '上传失败' })
  380. })
  381. }
  382. })
  383. },
  384. // 上传多张图片(不使用 Promise)
  385. uploadImages(filePaths, successCallback, failCallback) {
  386. const requestPath = uni.getStorageSync('requestPath') || 'http://t9794bec.natappfree.cc'
  387. const urls = []
  388. let completed = 0
  389. let hasError = false
  390. if (filePaths.length === 0) {
  391. successCallback([])
  392. return
  393. }
  394. filePaths.forEach((filePath, index) => {
  395. uni.uploadFile({
  396. url: `${requestPath}/app/common/uploadOSS`,
  397. filePath: filePath,
  398. name: 'file',
  399. success: (uploadRes) => {
  400. if (hasError) return
  401. try {
  402. const result = typeof uploadRes.data === 'string' ? JSON.parse(uploadRes.data) : uploadRes.data
  403. if (result.code == 200) {
  404. urls[index] = result.url || result.data?.url || ''
  405. } else {
  406. hasError = true
  407. failCallback(result.msg || '上传失败')
  408. return
  409. }
  410. } catch (e) {
  411. hasError = true
  412. failCallback('解析上传结果失败')
  413. return
  414. }
  415. completed++
  416. if (completed === filePaths.length) {
  417. successCallback(urls.filter(Boolean))
  418. }
  419. },
  420. fail: (err) => {
  421. if (hasError) return
  422. hasError = true
  423. failCallback('上传失败')
  424. }
  425. })
  426. })
  427. },
  428. removeTitleImage(index) {
  429. this.formData.titleCertificate.splice(index, 1)
  430. },
  431. previewImage(current, urls) {
  432. uni.previewImage({
  433. current: current,
  434. urls: urls
  435. })
  436. },
  437. goToPracticeExample() {
  438. uni.navigateTo({
  439. url: '/pages_user/practiceCertificateExample'
  440. })
  441. },
  442. goToTitleExample() {
  443. uni.navigateTo({
  444. url: '/pages_user/certificationExample'
  445. })
  446. },
  447. goToUserAgreement() {
  448. uni.navigateTo({
  449. url: '/pages_user/userAgreement'
  450. })
  451. },
  452. goToInformedConsent() {
  453. uni.navigateTo({
  454. url: '/pages_user/informedConsent'
  455. })
  456. },
  457. handleCancel() {
  458. uni.switchTab({
  459. url: '/pages/user/index'
  460. })
  461. },
  462. async handleSubmit() {
  463. // 表单验证
  464. if (!this.formData.doctorName && !this.formData.name) {
  465. uni.showToast({
  466. icon: 'none',
  467. title: '请输入姓名'
  468. })
  469. return
  470. }
  471. if (!this.formData.idCard && !this.formData.idNumber) {
  472. uni.showToast({
  473. icon: 'none',
  474. title: '请输入身份证号'
  475. })
  476. return
  477. }
  478. if (!this.formData.accountType) {
  479. uni.showToast({
  480. icon: 'none',
  481. title: '请选择账号身份'
  482. })
  483. return
  484. }
  485. if (!this.formData.institution) {
  486. uni.showToast({
  487. icon: 'none',
  488. title: '请输入机构名称'
  489. })
  490. return
  491. }
  492. if (!this.formData.department) {
  493. uni.showToast({
  494. icon: 'none',
  495. title: '请输入科室'
  496. })
  497. return
  498. }
  499. if (!this.formData.jobTitle && !this.formData.title) {
  500. uni.showToast({
  501. icon: 'none',
  502. title: '请输入职称'
  503. })
  504. return
  505. }
  506. // 至少上传一种证件
  507. if (this.formData.practiceCertificate.length === 0 && this.formData.titleCertificate.length === 0) {
  508. uni.showToast({
  509. icon: 'none',
  510. title: '请至少上传一种身份证明'
  511. })
  512. return
  513. }
  514. // 医师职业证至少上传2张
  515. if (this.formData.practiceCertificate.length > 0 && this.formData.practiceCertificate.length < 2) {
  516. uni.showToast({
  517. icon: 'none',
  518. title: '医师职业证至少需上传编码页和执业点页'
  519. })
  520. return
  521. }
  522. if (!this.formData.bankName && !this.formData.bank) {
  523. uni.showToast({
  524. icon: 'none',
  525. title: '请输入开户行'
  526. })
  527. return
  528. }
  529. if (!this.formData.bankBranch && !this.formData.branchName) {
  530. uni.showToast({
  531. icon: 'none',
  532. title: '请输入支行名称'
  533. })
  534. return
  535. }
  536. if (!this.formData.bankCardNo && !this.formData.bankCardNumber) {
  537. uni.showToast({
  538. icon: 'none',
  539. title: '请输入银行卡号'
  540. })
  541. return
  542. }
  543. if (!this.agreed) {
  544. uni.showToast({
  545. icon: 'none',
  546. title: '请阅读并同意用户协议和知情同意书'
  547. })
  548. return
  549. }
  550. try {
  551. uni.showLoading({ title: '提交中...' })
  552. // 获取图片URL(选择时已上传,直接使用)
  553. const licenseImageUrls = this.formData.practiceCertificate.filter(url => url && (url.startsWith('http://') || url.startsWith('https://')))
  554. const titleCertImageUrls = this.formData.titleCertificate.filter(url => url && (url.startsWith('http://') || url.startsWith('https://')))
  555. // 构建提交数据,按照接口字段要求
  556. const submitData = {
  557. accountType: this.formData.accountType, // 账户身份: 1-医生, 2-药剂师
  558. bankBranch: this.formData.bankBranch || this.formData.branchName, // 支行信息
  559. bankCardNo: this.formData.bankCardNo || this.formData.bankCardNumber, // 银行卡号
  560. bankName: this.formData.bankName || this.formData.bank, // 开户银行
  561. companyId: this.formData.companyId || '', // 公司ID
  562. companyName: this.formData.companyName || this.formData.institution, // 公司名称
  563. department: this.formData.department, // 科室
  564. doctorName: this.formData.doctorName || this.formData.name, // 讲者姓名
  565. idCard: this.formData.idCard || this.formData.idNumber, // 身份证号
  566. institution: this.formData.institution, // 机构名称
  567. jobTitle: this.formData.jobTitle || this.formData.title, // 职称
  568. licenseImage: licenseImageUrls.join(','), // 执业证图片URL(多个用逗号分隔)
  569. titleCertImage: titleCertImageUrls.join(',') // 职称证/工牌图片URL(多个用逗号分隔)
  570. }
  571. // 如果有id(编辑时),添加id字段
  572. if (this.formData.id) {
  573. submitData.id = this.formData.id
  574. }
  575. const res = await submitCertification(submitData)
  576. uni.hideLoading()
  577. if (res.code === 200) {
  578. uni.showToast({
  579. icon: 'success',
  580. title: '提交成功'
  581. })
  582. setTimeout(() => {
  583. uni.switchTab({
  584. url: '/pages/user/index'
  585. })
  586. }, 1500)
  587. } else {
  588. uni.showToast({
  589. icon: 'none',
  590. title: res.msg || '提交失败'
  591. })
  592. }
  593. } catch (e) {
  594. uni.hideLoading()
  595. console.error('提交认证失败', e)
  596. uni.showToast({
  597. icon: 'none',
  598. title: e.message || '提交失败'
  599. })
  600. }
  601. }
  602. }
  603. }
  604. </script>
  605. <style lang="stylus">
  606. .text-placeholder{
  607. color: #C8C9CC !important;
  608. }
  609. </style>
  610. <style lang="scss" scoped>
  611. .container {
  612. min-height: 100vh;
  613. background: #f5f5f5;
  614. display: flex;
  615. flex-direction: column;
  616. }
  617. .content {
  618. flex: 1;
  619. padding-bottom: 200rpx;
  620. box-sizing: border-box;
  621. }
  622. .rejection-banner {
  623. display: flex;
  624. align-items: center;
  625. padding: 24rpx;
  626. background: #FF5030;
  627. color: #fff;
  628. margin: 24rpx;
  629. border-radius: 8rpx;
  630. .rejection-icon {
  631. width: 40rpx;
  632. height: 40rpx;
  633. border-radius: 50%;
  634. background: rgba(255, 255, 255, 0.3);
  635. display: flex;
  636. align-items: center;
  637. justify-content: center;
  638. font-size: 24rpx;
  639. margin-right: 16rpx;
  640. }
  641. .rejection-text {
  642. flex: 1;
  643. font-size: 28rpx;
  644. line-height: 1.5;
  645. }
  646. }
  647. .form-section {
  648. background: #fff;
  649. margin: 20rpx;
  650. border-radius: 16rpx;
  651. padding: 32rpx;
  652. .section-header {
  653. display: flex;
  654. align-items: center;
  655. margin-bottom: 32rpx;
  656. .section-indicator {
  657. width: 6rpx;
  658. height: 32rpx;
  659. background: #388BFF;
  660. border-radius: 3rpx;
  661. margin-right: 16rpx;
  662. }
  663. .section-title {
  664. font-size: 32rpx;
  665. font-weight: bold;
  666. color: #333;
  667. }
  668. }
  669. .section-subtitle {
  670. font-size: 24rpx;
  671. color: #999;
  672. //margin-bottom: 24rpx;
  673. margin-left: 22rpx;
  674. }
  675. .form-item {
  676. margin-bottom: 32rpx;
  677. display: flex;
  678. align-items: center;
  679. border-bottom: 1px solid #EBEDF0;
  680. &:last-child {
  681. border-bottom: 0;
  682. margin-bottom: 0;
  683. }
  684. .form-label {
  685. display: flex;
  686. align-items: center;
  687. font-size: 28rpx;
  688. color: #333;
  689. // margin-bottom: 16rpx;
  690. width: 160rpx;
  691. .required {
  692. color: #FF5030;
  693. margin-right: 4rpx;
  694. }
  695. }
  696. .form-input {
  697. // width: 100%;
  698. flex:1;
  699. height: 80rpx;
  700. font-size: 28rpx;
  701. }
  702. .radio-group {
  703. flex: 1;
  704. display: flex;
  705. align-items: center;
  706. gap: 48rpx;
  707. height: 80rpx;
  708. .radio-item {
  709. display: flex;
  710. align-items: center;
  711. gap: 8rpx;
  712. .radio-text {
  713. font-size: 28rpx;
  714. color: #333;
  715. }
  716. }
  717. // padding: 0 24rpx;
  718. font-size: 28rpx;
  719. color: #333;
  720. &.placeholder {
  721. color: #C8C9CC;
  722. }
  723. &.picker-input {
  724. display: flex;
  725. align-items: center;
  726. justify-content: space-between;
  727. .arrow-right {
  728. font-size: 32rpx;
  729. color: #999;
  730. }
  731. }
  732. }
  733. }
  734. .certificate-item {
  735. padding-bottom: 32rpx;
  736. margin-bottom: 32rpx;
  737. border-bottom: 2rpx solid #F5F5F5;
  738. &:last-child {
  739. margin-bottom: 0;
  740. border-bottom: 0;
  741. }
  742. .certificate-header {
  743. display: flex;
  744. align-items: center;
  745. justify-content: space-between;
  746. margin-bottom: 24rpx;
  747. .certificate-title {
  748. font-size: 28rpx;
  749. color: #333;
  750. font-weight: 500;
  751. }
  752. .example-btn {
  753. display: flex;
  754. align-items: center;
  755. gap: 8rpx;
  756. font-size: 24rpx;
  757. color: #388BFF;
  758. .example-icon {
  759. width: 32rpx;
  760. height: 32rpx;
  761. border-radius: 50%;
  762. background: #E6F7FF;
  763. display: flex;
  764. align-items: center;
  765. justify-content: center;
  766. font-size: 20rpx;
  767. color: #388BFF;
  768. }
  769. }
  770. }
  771. .certificate-tip {
  772. font-size: 24rpx;
  773. color: #999;
  774. // margin-bottom: 16rpx;
  775. }
  776. .upload-grid {
  777. display: flex;
  778. gap: 16rpx;
  779. flex-wrap: wrap;
  780. .upload-item {
  781. width: 310rpx;
  782. height: 176rpx;
  783. border-radius: 8rpx;
  784. overflow: hidden;
  785. position: relative;
  786. .uploaded-image {
  787. width: 100%;
  788. height: 100%;
  789. }
  790. .bg{
  791. width: 100%;
  792. height: 100%;
  793. position: absolute;
  794. top: 0;
  795. left: 0;
  796. }
  797. .delete-btn {
  798. position: absolute;
  799. top: 0;
  800. right: 0;
  801. width: 40rpx;
  802. height: 40rpx;
  803. line-height: 40rpx;
  804. background: rgba(0, 0, 0, 0.5);
  805. border-radius: 50%;
  806. display: flex;
  807. align-items: center;
  808. justify-content: center;
  809. font-size: 32rpx;
  810. color: #fff;
  811. }
  812. &.upload-placeholder {
  813. background: #f5f5f5;
  814. display: flex;
  815. flex-direction: column;
  816. align-items: center;
  817. justify-content: center;
  818. // border: 2rpx dashed #ddd;
  819. .img-btn{
  820. z-index: 1;
  821. display: flex;
  822. flex-direction: column;
  823. align-items: center;
  824. justify-content: center;
  825. }
  826. .camera-icon {
  827. font-size: 60rpx;
  828. margin-bottom: 8rpx;
  829. }
  830. .upload-text {
  831. font-size: 24rpx;
  832. color: #388BFF;
  833. }
  834. }
  835. }
  836. }
  837. }
  838. }
  839. .bottom-bar {
  840. position: fixed;
  841. bottom: 0;
  842. left: 0;
  843. right: 0;
  844. background: #fff;
  845. padding: 24rpx;
  846. // border-top: 1rpx solid #f0f0f0;
  847. z-index: 100;
  848. .agreement-checkbox {
  849. margin-bottom: 24rpx;
  850. margin-top: 20rpx;
  851. .checkbox-label {
  852. display: flex;
  853. align-items: flex-start;
  854. font-size: 24rpx;
  855. color: #666;
  856. .agreement-text {
  857. margin-left: 8rpx;
  858. line-height: 1.5;
  859. .link-text {
  860. color: #388BFF;
  861. }
  862. }
  863. }
  864. }
  865. .action-buttons {
  866. display: flex;
  867. gap: 24rpx;
  868. .btn {
  869. flex: 1;
  870. height: 88rpx;
  871. display: flex;
  872. align-items: center;
  873. justify-content: center;
  874. border-radius: 8rpx;
  875. font-size: 32rpx;
  876. font-weight: 500;
  877. border-radius: 200rpx 200rpx 200rpx 200rpx;
  878. &.btn-cancel {
  879. background: #fff;
  880. border: 2rpx solid #388BFF;
  881. color: #388BFF;
  882. }
  883. &.btn-submit {
  884. background: #388BFF;
  885. color: #fff;
  886. }
  887. }
  888. }
  889. }
  890. </style>