setUserInfo.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. <template>
  2. <view class="set-user-info-container">
  3. <!-- 标题 -->
  4. <view class="page-title">完善个人信息</view>
  5. <scroll-view class="form-scroll" scroll-y>
  6. <!-- 头像上传 -->
  7. <view class="avatar-section">
  8. <view class="avatar-wrapper" @click="chooseAvatar">
  9. <image v-if="formData.avatar" :src="formData.avatar" class="avatar-image" mode="aspectFill" />
  10. <view v-else class="avatar-placeholder">
  11. <image src="/static/images/login/user.png" class="avatar-image" mode="aspectFill" style="width: 80%; height: 80%;" />
  12. </view>
  13. </view>
  14. <view class="avatar-tip">
  15. <text class="tip-text">点击上传头像</text>
  16. <text class="required-mark">*</text>
  17. </view>
  18. <view v-if="errors.avatar" class="error-tip">{{ errors.avatar }}</view>
  19. </view>
  20. <!-- 表单字段 -->
  21. <view class="form-section">
  22. <!-- 真实姓名 -->
  23. <view class="form-item">
  24. <view class="form-label">
  25. <text>真实姓名</text>
  26. <text class="required-mark">*</text>
  27. </view>
  28. <input v-model="formData.realName" class="form-input" placeholder="请输入真实姓名"
  29. @blur="validateField('realName')" />
  30. <view v-if="errors.realName" class="error-tip">{{ errors.realName }}</view>
  31. </view>
  32. <!-- 从业时间 -->
  33. <view class="form-item">
  34. <view class="form-label">
  35. <text>从业时间</text>
  36. <text class="required-mark">*</text>
  37. </view>
  38. <picker mode="date" :value="formData.practiceYear" :start="startDate" :end="endDate"
  39. @change="onPracticeYearChange">
  40. <view class="picker-view">
  41. <text :class="formData.practiceYear ? 'picker-text' : 'picker-placeholder'">
  42. {{ formData.practiceYear ? formatDate(formData.practiceYear) : '请选择从业时间' }}
  43. </text>
  44. <text class="picker-arrow">›</text>
  45. </view>
  46. </picker>
  47. <view v-if="errors.practiceYear" class="error-tip">{{ errors.practiceYear }}</view>
  48. </view>
  49. <!-- 专业领域 -->
  50. <view class="form-item">
  51. <view class="form-label">
  52. <text>专业领域</text>
  53. <text class="required-mark">*</text>
  54. </view>
  55. <picker mode="selector" :range="professionalFields" :value="professionalFieldIndex"
  56. @change="onProfessionalFieldChange">
  57. <view class="picker-view">
  58. <text :class="formData.professionalField ? 'picker-text' : 'picker-placeholder'">
  59. {{ formData.professionalField || '请选择专业领域' }}
  60. </text>
  61. <text class="picker-arrow">›</text>
  62. </view>
  63. </picker>
  64. <view v-if="errors.professionalField" class="error-tip">{{ errors.professionalField }}</view>
  65. </view>
  66. <!-- 法律场景 -->
  67. <view class="form-item">
  68. <view class="form-label">
  69. <text>法律场景</text>
  70. <text class="required-mark">*</text>
  71. </view>
  72. <view class="picker-view" @click="showLegalScenarioModal = true">
  73. <view class="picker-text-ellipsis">
  74. <text :class="formData.legalScenarios && formData.legalScenarios.length > 0 ? 'picker-text' : 'picker-placeholder'">
  75. {{ getLegalScenarioText() || '请选择法律场景' }}
  76. </text>
  77. </view>
  78. <text class="picker-arrow">›</text>
  79. </view>
  80. <view v-if="errors.legalScenario" class="error-tip">{{ errors.legalScenario }}</view>
  81. </view>
  82. <!-- 联系地址 -->
  83. <view class="form-item">
  84. <view class="form-label">
  85. <text>联系地址</text>
  86. <text class="required-mark">*</text>
  87. </view>
  88. <input v-model="formData.address" class="form-input" placeholder="请输入常用联系地址"
  89. @blur="validateField('address')" />
  90. <view v-if="errors.address" class="error-tip">{{ errors.address }}</view>
  91. </view>
  92. <!-- 律师事务所名称 -->
  93. <view class="form-item">
  94. <view class="form-label">
  95. <text>律师事务所名称</text>
  96. <text class="required-mark">*</text>
  97. </view>
  98. <picker
  99. mode="selector"
  100. :range="firmList"
  101. range-key="firmName"
  102. :value="lawFirmIndex"
  103. @change="onLawFirmChange"
  104. >
  105. <view class="picker-view">
  106. <text :class="formData.lawFirmName ? 'picker-text' : 'picker-placeholder'">
  107. {{ formData.lawFirmName || '请选择律师事务所名称' }}
  108. </text>
  109. <text class="picker-arrow">›</text>
  110. </view>
  111. </picker>
  112. <view v-if="errors.lawFirmName" class="error-tip">{{ errors.lawFirmName }}</view>
  113. </view>
  114. <!-- 律师事务所收款账号 -->
  115. <view class="form-item">
  116. <view class="form-label">
  117. <text>律师事务所收款账号</text>
  118. <text class="required-mark">*</text>
  119. </view>
  120. <picker
  121. mode="selector"
  122. :range="paymentAccountList"
  123. :value="paymentAccountIndex"
  124. @change="onPaymentAccountChange"
  125. >
  126. <view class="picker-view">
  127. <text :class="formData.paymentAccount ? 'picker-text' : 'picker-placeholder'">
  128. {{ formData.paymentAccount || '请选择律师事务所收款账号' }}
  129. </text>
  130. <text class="picker-arrow">›</text>
  131. </view>
  132. </picker>
  133. <view v-if="errors.paymentAccount" class="error-tip">{{ errors.paymentAccount }}</view>
  134. </view>
  135. <!-- 律师资格证 -->
  136. <view class="form-item">
  137. <view class="form-label">
  138. <text>律师资格证</text>
  139. <text class="required-mark">*</text>
  140. </view>
  141. <view class="certificate-upload" @click="chooseCertificate">
  142. <image v-if="formData.certificate" :src="formData.certificate" class="certificate-image"
  143. mode="aspectFit" />
  144. <view v-else class="certificate-placeholder">
  145. <text class="certificate-icon">🏔️</text>
  146. <text class="certificate-text">点击上传图片</text>
  147. </view>
  148. </view>
  149. <view v-if="errors.certificate" class="error-tip">{{ errors.certificate }}</view>
  150. </view>
  151. </view>
  152. </scroll-view>
  153. <!-- 提交按钮 -->
  154. <view class="submit-section">
  155. <button class="submit-btn" @click="handleSubmit">提交信息</button>
  156. </view>
  157. <!-- 法律场景多选弹窗 -->
  158. <view class="modal-overlay" v-if="showLegalScenarioModal" @click="showLegalScenarioModal = false">
  159. <view class="legal-scenario-modal" @click.stop>
  160. <view class="modal-header">
  161. <view class="modal-title">选择您擅长的法律场景</view>
  162. <text class="cancel-btn" @click="showLegalScenarioModal = false">取消</text>
  163. </view>
  164. <view class="scenario-tags">
  165. <view
  166. v-for="(scenario, index) in legalScenarios"
  167. :key="index"
  168. class="scenario-tag"
  169. :class="{ 'selected': isLegalScenarioSelected(scenario) }"
  170. @click="toggleLegalScenario(scenario)"
  171. >
  172. {{ scenario }}
  173. </view>
  174. </view>
  175. <button class="confirm-btn" @click="confirmLegalScenarios">选好了</button>
  176. </view>
  177. </view>
  178. </view>
  179. </template>
  180. <script>
  181. import upload from '@/utils/upload'
  182. import { updateUserProfile, uploadAvatar } from '@/api/system/user'
  183. import { getFirmList, getLegalProblemScenarioList, getExpertiseAreaList } from '@/api/setUserInfo'
  184. import { getToken } from '@/utils/auth'
  185. import config from '@/config'
  186. export default {
  187. data() {
  188. return {
  189. formData: {
  190. avatar: '',
  191. realName: '',
  192. practiceYear: '',
  193. professionalField: '',
  194. legalScenarios: [], // 改为数组支持多选
  195. address: '',
  196. paymentAccount: '',
  197. lawFirmName: '',
  198. certificate: ''
  199. },
  200. errors: {},
  201. startDate: '1950-01-01', // 最早可选日期
  202. endDate: '', // 最晚可选日期(今天)
  203. professionalFields: ['刑事法律', '民事法律', '商事法律', '行政法律', '知识产权', '劳动法律', '其他'],
  204. professionalFieldIndex: -1,
  205. legalScenarios: ['家庭生活', '职场工作', '邻里与社区', '网络与数字', '交通出行', '居住与物业', '消费与服务'],
  206. showLegalScenarioModal: false,
  207. firmList: [], // 律师事务所列表
  208. lawFirmIndex: -1,
  209. paymentAccountList: [], // 收款账号列表
  210. paymentAccountIndex: -1,
  211. baseUrl: config.baseUrl
  212. }
  213. },
  214. onLoad() {
  215. // 设置最晚可选日期为今天
  216. const today = new Date()
  217. const year = today.getFullYear()
  218. const month = String(today.getMonth() + 1).padStart(2, '0')
  219. const day = String(today.getDate()).padStart(2, '0')
  220. this.endDate = `${year}-${month}-${day}`
  221. // 加载律师事务所列表
  222. // this.getPageInfo()
  223. },
  224. methods: {
  225. getPageInfo() {
  226. getFirmList().then(res => {
  227. if (res.data && res.data.length > 0) {
  228. this.firmList = res.data
  229. // 提取收款账号列表(假设每个律师事务所都有收款账号字段)
  230. this.paymentAccountList = res.data.map(item => item.paymentAccount || item.account || '').filter(account => account)
  231. }
  232. }).catch(() => {
  233. // 如果接口失败,使用默认数据
  234. this.firmList = []
  235. this.paymentAccountList = []
  236. })
  237. },
  238. // 律师事务所选择
  239. onLawFirmChange(e) {
  240. this.lawFirmIndex = e.detail.value
  241. const selectedFirm = this.firmList[e.detail.value]
  242. if (selectedFirm) {
  243. this.formData.lawFirmName = selectedFirm.firmName || selectedFirm.name || ''
  244. // 如果选择的律师事务所有收款账号,自动填充
  245. if (selectedFirm.paymentAccount || selectedFirm.account) {
  246. this.formData.paymentAccount = selectedFirm.paymentAccount || selectedFirm.account
  247. // 找到对应的收款账号索引
  248. const accountIndex = this.paymentAccountList.indexOf(this.formData.paymentAccount)
  249. if (accountIndex > -1) {
  250. this.paymentAccountIndex = accountIndex
  251. }
  252. }
  253. this.errors.lawFirmName = ''
  254. }
  255. },
  256. // 收款账号选择
  257. onPaymentAccountChange(e) {
  258. this.paymentAccountIndex = e.detail.value
  259. this.formData.paymentAccount = this.paymentAccountList[e.detail.value] || ''
  260. this.errors.paymentAccount = ''
  261. },
  262. // 选择头像
  263. chooseAvatar() {
  264. uni.chooseImage({
  265. count: 1,
  266. sizeType: ['compressed'],
  267. sourceType: ['album', 'camera'],
  268. success: (res) => {
  269. const tempFilePath = res.tempFilePaths[0]
  270. this.uploadAvatarFile(tempFilePath)
  271. }
  272. })
  273. },
  274. // 上传头像
  275. uploadAvatarFile(filePath) {
  276. this.$modal.loading('上传中...')
  277. uni.uploadFile({
  278. url: 'http://192.168.2.54:8899/file/upload',
  279. filePath: filePath,
  280. name: 'avatarfile',
  281. header: {
  282. 'Authorization': 'Bearer ' + (getToken() || '')
  283. },
  284. success: (res) => {
  285. try {
  286. const result = JSON.parse(res.data)
  287. if (result.code === 200) {
  288. this.$modal.closeLoading()
  289. this.formData.avatar = this.baseUrl + result.imgUrl
  290. this.errors.avatar = ''
  291. } else {
  292. this.$modal.closeLoading()
  293. this.$modal.msgError(result.msg || '上传失败')
  294. }
  295. } catch (e) {
  296. this.$modal.closeLoading()
  297. this.$modal.msgError('上传失败')
  298. }
  299. },
  300. fail: (error) => {
  301. this.$modal.closeLoading()
  302. this.$modal.msgError('上传失败')
  303. }
  304. })
  305. },
  306. // 选择律师资格证
  307. chooseCertificate() {
  308. uni.chooseImage({
  309. count: 1,
  310. sizeType: ['compressed'],
  311. sourceType: ['album', 'camera'],
  312. success: (res) => {
  313. const tempFilePath = res.tempFilePaths[0]
  314. this.uploadCertificateFile(tempFilePath)
  315. }
  316. })
  317. },
  318. // 上传资格证
  319. uploadCertificateFile(filePath) {
  320. this.$modal.loading('上传中...')
  321. upload({
  322. url: '/system/user/profile/certificate',
  323. name: 'certificate',
  324. filePath: filePath
  325. }).then(res => {
  326. this.$modal.closeLoading()
  327. this.formData.certificate = this.baseUrl + res.imgUrl
  328. this.errors.certificate = ''
  329. }).catch(() => {
  330. this.$modal.closeLoading()
  331. })
  332. },
  333. // 从业时间选择
  334. onPracticeYearChange(e) {
  335. this.formData.practiceYear = e.detail.value
  336. this.errors.practiceYear = ''
  337. },
  338. // 格式化日期显示
  339. formatDate(dateStr) {
  340. if (!dateStr) return ''
  341. const date = new Date(dateStr)
  342. const year = date.getFullYear()
  343. const month = String(date.getMonth() + 1).padStart(2, '0')
  344. const day = String(date.getDate()).padStart(2, '0')
  345. return `${year}年${month}月${day}日`
  346. },
  347. // 专业领域选择
  348. onProfessionalFieldChange(e) {
  349. this.professionalFieldIndex = e.detail.value
  350. this.formData.professionalField = this.professionalFields[e.detail.value]
  351. this.errors.professionalField = ''
  352. },
  353. // 获取法律场景显示文本
  354. getLegalScenarioText() {
  355. if (!this.formData.legalScenarios || this.formData.legalScenarios.length === 0) {
  356. return ''
  357. }
  358. return this.formData.legalScenarios.join('、')
  359. },
  360. // 判断法律场景是否已选中
  361. isLegalScenarioSelected(scenario) {
  362. return this.formData.legalScenarios && this.formData.legalScenarios.includes(scenario)
  363. },
  364. // 切换法律场景选择状态
  365. toggleLegalScenario(scenario) {
  366. if (!this.formData.legalScenarios) {
  367. this.formData.legalScenarios = []
  368. }
  369. const index = this.formData.legalScenarios.indexOf(scenario)
  370. if (index > -1) {
  371. // 已选中,取消选择
  372. this.formData.legalScenarios.splice(index, 1)
  373. } else {
  374. // 未选中,添加选择
  375. this.formData.legalScenarios.push(scenario)
  376. }
  377. },
  378. // 确认法律场景选择
  379. confirmLegalScenarios() {
  380. if (this.formData.legalScenarios && this.formData.legalScenarios.length > 0) {
  381. this.errors.legalScenario = ''
  382. }
  383. this.showLegalScenarioModal = false
  384. },
  385. // 验证单个字段
  386. validateField(field) {
  387. this.errors[field] = ''
  388. const value = this.formData[field]
  389. if (!value || value.trim() === '') {
  390. switch (field) {
  391. case 'realName':
  392. this.errors.realName = '请填写真实姓名'
  393. break
  394. case 'address':
  395. this.errors.address = '请填写联系地址'
  396. break
  397. case 'paymentAccount':
  398. this.errors.paymentAccount = '请选择律师事务所收款账号'
  399. break
  400. case 'lawFirmName':
  401. this.errors.lawFirmName = '请选择律师事务所名称'
  402. break
  403. }
  404. }
  405. },
  406. // 验证所有字段
  407. validateForm() {
  408. this.errors = {}
  409. let isValid = true
  410. if (!this.formData.avatar) {
  411. this.errors.avatar = '请上传头像'
  412. isValid = false
  413. }
  414. if (!this.formData.realName || this.formData.realName.trim() === '') {
  415. this.errors.realName = '请填写真实姓名'
  416. isValid = false
  417. }
  418. if (!this.formData.practiceYear) {
  419. this.errors.practiceYear = '请选择从业时间'
  420. isValid = false
  421. }
  422. if (!this.formData.professionalField) {
  423. this.errors.professionalField = '请选择专业领域'
  424. isValid = false
  425. }
  426. if (!this.formData.legalScenarios || this.formData.legalScenarios.length === 0) {
  427. this.errors.legalScenario = '请选择法律场景'
  428. isValid = false
  429. }
  430. if (!this.formData.address || this.formData.address.trim() === '') {
  431. this.errors.address = '请填写联系地址'
  432. isValid = false
  433. }
  434. if (!this.formData.paymentAccount || this.formData.paymentAccount.trim() === '') {
  435. this.errors.paymentAccount = '请选择律师事务所收款账号'
  436. isValid = false
  437. }
  438. if (!this.formData.lawFirmName || this.formData.lawFirmName.trim() === '') {
  439. this.errors.lawFirmName = '请选择律师事务所名称'
  440. isValid = false
  441. }
  442. if (!this.formData.certificate) {
  443. this.errors.certificate = '请上传律师资格证'
  444. isValid = false
  445. }
  446. return isValid
  447. },
  448. // 提交表单
  449. handleSubmit() {
  450. if (!this.validateForm()) {
  451. this.$modal.msgError('请完善所有必填信息')
  452. return
  453. }
  454. this.$modal.loading('提交中...')
  455. updateUserProfile(this.formData).then(() => {
  456. this.$modal.closeLoading()
  457. this.$modal.msgSuccess('提交成功')
  458. setTimeout(() => {
  459. uni.navigateBack()
  460. }, 1500)
  461. }).catch(() => {
  462. this.$modal.closeLoading()
  463. })
  464. }
  465. }
  466. }
  467. </script>
  468. <style lang="scss" scoped>
  469. page {
  470. background-color: #F9FAFC;
  471. }
  472. input,.picker-view {
  473. background-color: #fff !important;
  474. width: 676rpx;
  475. height: 103rpx;
  476. background: #FFFFFF;
  477. box-shadow: 0rpx 2rpx 11rpx 0rpx rgba(0, 0, 0, 0.06);
  478. border-radius: 23rpx 23rpx 23rpx 23rpx;
  479. }
  480. .set-user-info-container {
  481. min-height: 100vh;
  482. padding-bottom: 120rpx;
  483. }
  484. .page-title {
  485. font-size: 36rpx;
  486. font-weight: bold;
  487. color: #333;
  488. text-align: center;
  489. padding: 40rpx 0 30rpx;
  490. // background-color: #fff;
  491. }
  492. .form-scroll {
  493. height: calc(100vh - 200rpx);
  494. padding: 0 30rpx;
  495. }
  496. .avatar-section {
  497. // background-color: #F9FAFC;
  498. padding: 40rpx 0;
  499. margin-bottom: 20rpx;
  500. border-radius: 16rpx;
  501. display: flex;
  502. flex-direction: column;
  503. align-items: center;
  504. }
  505. .avatar-wrapper {
  506. position: relative;
  507. width: 160rpx;
  508. height: 160rpx;
  509. border-radius: 50%;
  510. overflow: hidden;
  511. // background-color: #f0f0f0;
  512. margin-bottom: 20rpx;
  513. }
  514. .avatar-image {
  515. width: 100%;
  516. height: 100%;
  517. }
  518. .avatar-placeholder {
  519. width: 100%;
  520. height: 100%;
  521. display: flex;
  522. align-items: center;
  523. justify-content: center;
  524. // background-color: #f0f0f0;
  525. }
  526. .avatar-icon {
  527. font-size: 80rpx;
  528. color: #ccc;
  529. }
  530. .camera-icon {
  531. position: absolute;
  532. bottom: 0;
  533. right: 0;
  534. width: 48rpx;
  535. height: 48rpx;
  536. background-color: #4a90e2;
  537. border-radius: 50%;
  538. display: flex;
  539. align-items: center;
  540. justify-content: center;
  541. border: 3rpx solid #fff;
  542. }
  543. .camera-text {
  544. font-size: 24rpx;
  545. }
  546. .avatar-tip {
  547. display: flex;
  548. align-items: center;
  549. font-size: 28rpx;
  550. color: #4a90e2;
  551. }
  552. .tip-text {
  553. margin-right: 4rpx;
  554. }
  555. .required-mark {
  556. color: #ff4d4f;
  557. font-size: 28rpx;
  558. }
  559. .form-section {
  560. // background-color: #fff;
  561. border-radius: 16rpx;
  562. padding: 30rpx;
  563. margin-bottom: 20rpx;
  564. }
  565. .form-item {
  566. margin-bottom: 40rpx;
  567. &:last-child {
  568. margin-bottom: 0;
  569. }
  570. }
  571. .form-label {
  572. font-size: 28rpx;
  573. color: #333;
  574. margin-bottom: 20rpx;
  575. display: flex;
  576. align-items: center;
  577. }
  578. .form-input {
  579. width: 100%;
  580. height: 80rpx;
  581. background-color: #f8f9fa;
  582. border-radius: 12rpx;
  583. padding: 0 24rpx;
  584. font-size: 28rpx;
  585. color: #333;
  586. box-sizing: border-box;
  587. }
  588. .picker-view {
  589. width: 100%;
  590. height: 80rpx;
  591. background-color: #f8f9fa;
  592. border-radius: 12rpx;
  593. padding: 0 24rpx;
  594. display: flex;
  595. align-items: center;
  596. justify-content: space-between;
  597. box-sizing: border-box;
  598. }
  599. .picker-text {
  600. font-size: 28rpx;
  601. color: #333;
  602. }
  603. .picker-placeholder {
  604. font-size: 28rpx;
  605. color: #999;
  606. }
  607. .picker-text-ellipsis {
  608. flex: 1;
  609. overflow: hidden;
  610. text-overflow: ellipsis;
  611. white-space: nowrap;
  612. margin-right: 20rpx;
  613. }
  614. .picker-arrow {
  615. font-size: 40rpx;
  616. color: #999;
  617. font-weight: 300;
  618. }
  619. .certificate-upload {
  620. width: 100%;
  621. height: 300rpx;
  622. border: 2rpx dashed #ddd;
  623. border-radius: 12rpx;
  624. display: flex;
  625. align-items: center;
  626. justify-content: center;
  627. background-color: #fafafa;
  628. box-sizing: border-box;
  629. }
  630. .certificate-image {
  631. width: 100%;
  632. height: 100%;
  633. border-radius: 12rpx;
  634. }
  635. .certificate-placeholder {
  636. display: flex;
  637. flex-direction: column;
  638. align-items: center;
  639. justify-content: center;
  640. }
  641. .certificate-icon {
  642. font-size: 80rpx;
  643. margin-bottom: 20rpx;
  644. }
  645. .certificate-text {
  646. font-size: 28rpx;
  647. color: #999;
  648. }
  649. .error-tip {
  650. font-size: 24rpx;
  651. color: #ff4d4f;
  652. margin-top: 10rpx;
  653. padding: 8rpx 16rpx;
  654. background-color: #fff2f0;
  655. border-radius: 8rpx;
  656. display: inline-block;
  657. }
  658. .submit-section {
  659. position: fixed;
  660. bottom: 0;
  661. left: 0;
  662. right: 0;
  663. padding: 20rpx 30rpx;
  664. padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
  665. background-color: #fff;
  666. box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
  667. }
  668. .submit-btn {
  669. width: 100%;
  670. height: 88rpx;
  671. background: linear-gradient(135deg, #4a90e2 0%, #5ba0f2 100%);
  672. color: #fff;
  673. font-size: 32rpx;
  674. border-radius: 16rpx;
  675. border: none;
  676. display: flex;
  677. align-items: center;
  678. justify-content: center;
  679. }
  680. uni-button:after {
  681. border: none !important;
  682. }
  683. .modal-overlay {
  684. position: fixed;
  685. top: 0;
  686. left: 0;
  687. right: 0;
  688. bottom: 0;
  689. background: rgba(0, 0, 0, 0.5);
  690. // display: flex;
  691. // align-items: center;
  692. // justify-content: center;
  693. z-index: 1000;
  694. }
  695. .legal-scenario-modal {
  696. width: 100%;
  697. background: #fff;
  698. border-radius: 24rpx 24rpx 0 0;
  699. padding: 40rpx 30rpx 30rpx;
  700. max-height: 80vh;
  701. display: flex;
  702. flex-direction: column;
  703. position: fixed;
  704. left: 0;
  705. bottom: 0;
  706. }
  707. .modal-header {
  708. position: relative;
  709. display: flex;
  710. justify-content: center;
  711. align-items: center;
  712. margin-bottom: 40rpx;
  713. padding: 0 60rpx;
  714. }
  715. .modal-title {
  716. font-size: 32rpx;
  717. font-weight: bold;
  718. color: #333;
  719. text-align: center;
  720. }
  721. .cancel-btn {
  722. font-size: 28rpx;
  723. color: #999;
  724. position: absolute;
  725. right: 30rpx;
  726. top: 50%;
  727. transform: translateY(-50%);
  728. }
  729. .scenario-tags {
  730. display: flex;
  731. flex-wrap: wrap;
  732. gap: 20rpx;
  733. margin-bottom: 40rpx;
  734. max-height: 50vh;
  735. overflow-y: auto;
  736. }
  737. .scenario-tag {
  738. min-width: 200rpx;
  739. height: 70rpx;
  740. background-color: #f5f5f5;
  741. border-radius: 45rpx;
  742. display: flex;
  743. align-items: center;
  744. justify-content: center;
  745. font-size: 28rpx;
  746. color: #666;
  747. flex: 0 0 calc(33.333% - 14rpx);
  748. box-sizing: border-box;
  749. transition: all 0.3s;
  750. }
  751. .scenario-tag.selected {
  752. background:#ECF1FE;
  753. color: #2652C2;
  754. }
  755. .confirm-btn {
  756. width: 100%;
  757. height: 88rpx;
  758. background: linear-gradient(135deg, #4a90e2 0%, #5ba0f2 100%);
  759. color: #fff;
  760. font-size: 32rpx;
  761. border-radius: 16rpx;
  762. border: none;
  763. display: flex;
  764. align-items: center;
  765. justify-content: center;
  766. }
  767. </style>