木邻有你前端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

544 lines
15 KiB

10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
  1. <template>
  2. <view class="volunteer-apply-page">
  3. <!-- 头部背景图 -->
  4. <view class="header-section">
  5. <image src="../static/volunteer_bg@2x.png" class="bg-image" mode="aspectFit"></image>
  6. </view>
  7. <!-- 提示信息 -->
  8. <view class="tip-section">
  9. <uv-icon name="info-circle-fill" color="#1488DB" size="32"></uv-icon>
  10. <text class="tip-text">以下内容均为必填项请根据您的实际情况认真填写</text>
  11. </view>
  12. <!-- 表单内容 -->
  13. <view class="form-section">
  14. <uv-form ref="form" :model="formData" :rules="rules" labelPosition="left" labelWidth="120">
  15. <!-- 姓名 -->
  16. <uv-form-item label="姓名" prop="name" borderBottom>
  17. <uv-input
  18. v-model="formData.name"
  19. placeholder="请输入您的姓名"
  20. border="none"
  21. clearable
  22. ></uv-input>
  23. </uv-form-item>
  24. <!-- 手机号 -->
  25. <uv-form-item label="手机号" prop="phone" borderBottom>
  26. <uv-input
  27. v-model="formData.phone"
  28. placeholder="请输入您的手机号"
  29. border="none"
  30. clearable
  31. type="number"
  32. ></uv-input>
  33. </uv-form-item>
  34. <!-- 性别 -->
  35. <uv-form-item label="性别" prop="sex" borderBottom @click="openGenderPicker">
  36. <uv-input
  37. v-model="formData.sex"
  38. placeholder="请选择"
  39. border="none"
  40. readonly
  41. suffixIcon="arrow-right"
  42. ></uv-input>
  43. </uv-form-item>
  44. <!-- 所在地区 -->
  45. <uv-form-item label="所在地区" prop="area" borderBottom @click="openRegionPicker">
  46. <uv-input
  47. v-model="formData.area"
  48. placeholder="请选择"
  49. border="none"
  50. readonly
  51. suffixIcon="arrow-right"
  52. ></uv-input>
  53. </uv-form-item>
  54. <!-- 详细地址 -->
  55. <uv-form-item label="详细地址" prop="address" borderBottom>
  56. <uv-input
  57. v-model="formData.address"
  58. placeholder="请输入详细地址"
  59. border="none"
  60. clearable
  61. ></uv-input>
  62. </uv-form-item>
  63. <!-- 职业类型 -->
  64. <uv-form-item label="职业类型" prop="career" borderBottom @click="openProfessionPicker">
  65. <uv-input
  66. v-model="formData.career"
  67. placeholder="请选择"
  68. border="none"
  69. readonly
  70. suffixIcon="arrow-right"
  71. ></uv-input>
  72. </uv-form-item>
  73. <!-- 最高学历 -->
  74. <uv-form-item label="最高学历" prop="qualifications" borderBottom @click="openEducationPicker">
  75. <uv-input
  76. v-model="formData.qualifications"
  77. placeholder="请选择"
  78. border="none"
  79. readonly
  80. suffixIcon="arrow-right"
  81. ></uv-input>
  82. </uv-form-item>
  83. <!-- 技能特长 -->
  84. <uv-form-item label="技能特长" prop="skill">
  85. <uv-textarea
  86. v-model="formData.skill"
  87. placeholder="请输入您的技能特长"
  88. border="none"
  89. :maxlength="200"
  90. count
  91. height="120"
  92. ></uv-textarea>
  93. </uv-form-item>
  94. </uv-form>
  95. <!-- 紧急联系人信息 -->
  96. <view class="emergency-section">
  97. <view class="section-title">紧急联系人信息</view>
  98. <uv-form ref="emergencyForm" :model="emergencyData" labelPosition="left" labelWidth="120">
  99. <!-- 联系人姓名 -->
  100. <uv-form-item label="姓名" prop="emergencyName" borderBottom>
  101. <uv-input
  102. v-model="emergencyData.emergencyName"
  103. placeholder="请输入您的紧急联系人姓名"
  104. border="none"
  105. clearable
  106. ></uv-input>
  107. </uv-form-item>
  108. <!-- 联系人手机号 -->
  109. <uv-form-item label="手机号" prop="emergencyPhone" borderBottom>
  110. <uv-input
  111. v-model="emergencyData.emergencyPhone"
  112. placeholder="请输入您的紧急联系人手机号"
  113. border="none"
  114. clearable
  115. type="number"
  116. ></uv-input>
  117. </uv-form-item>
  118. </uv-form>
  119. </view>
  120. </view>
  121. <!-- 提交按钮 -->
  122. <view class="submit-section">
  123. <!-- 圆角的 -->
  124. <uv-button
  125. type="primary"
  126. shape="circle"
  127. size="large"
  128. :loading="submitting"
  129. @click="submitApplication"
  130. >
  131. 提交申请
  132. </uv-button>
  133. </view>
  134. <!-- 性别选择器 -->
  135. <uv-picker
  136. ref="genderPicker"
  137. :columns="genderOptions"
  138. @confirm="onGenderConfirm"
  139. ></uv-picker>
  140. <!-- 地区选择器 -->
  141. <uv-picker
  142. ref="regionPicker"
  143. :columns="addressList"
  144. @confirm="onAddressConfirm"
  145. @change="onAddressChange"
  146. keyName="name"
  147. ></uv-picker>
  148. <!-- 职业选择器 -->
  149. <uv-picker
  150. ref="professionPicker"
  151. :columns="professionOptions"
  152. @confirm="onProfessionConfirm"
  153. ></uv-picker>
  154. <!-- 学历选择器 -->
  155. <uv-picker
  156. ref="educationPicker"
  157. :columns="educationOptions"
  158. @confirm="onEducationConfirm"
  159. ></uv-picker>
  160. </view>
  161. </template>
  162. <script>
  163. import chinaRegions from '@/static/china-regions.json'
  164. export default {
  165. name: 'VolunteerApply',
  166. data() {
  167. return {
  168. submitting: false,
  169. formData: {
  170. name: '',
  171. phone: '',
  172. sex: '',
  173. // sexText: '',
  174. area: '',
  175. address: '',
  176. career: '',
  177. // careerText: '',
  178. qualifications: '',
  179. // qualificationsText: '',
  180. skill: ''
  181. },
  182. emergencyData: {
  183. emergencyName: '',
  184. emergencyPhone: ''
  185. },
  186. rules: {
  187. name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
  188. phone: [
  189. { required: true, message: '请输入手机号', trigger: 'blur' },
  190. { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
  191. ],
  192. sex: [{ required: true, message: '请选择性别', trigger: 'change' }],
  193. area: [{ required: true, message: '请选择所在地区', trigger: 'change' }],
  194. address: [{ required: true, message: '请输入详细地址', trigger: 'blur' }],
  195. career: [{ required: true, message: '请选择职业类型', trigger: 'change' }],
  196. qualifications: [{ required: true, message: '请选择最高学历', trigger: 'change' }]
  197. },
  198. genderOptions: [['男', '女']],
  199. provinces: [], //省
  200. citys: [], //市
  201. areas: [], //区
  202. pickerValue: [0, 0, 0],
  203. defaultValue: [3442, 1, 2],
  204. // professionOptions: [[
  205. // '学生', '教师', '医生', '工程师', '设计师', '销售',
  206. // '服务员', '公务员', '自由职业', '专业技术人员', '其他'
  207. // ]],
  208. // educationOptions: [[
  209. // '高中及以下', '大专', '本科', '硕士', '博士'
  210. // ]]
  211. }
  212. },
  213. computed: {
  214. addressList() {
  215. return [this.provinces, this.citys, this.areas];
  216. },
  217. professionOptions() {
  218. return [this.$store.state.careerList.map(item => item.title)]
  219. },
  220. educationOptions() {
  221. return [this.$store.state.qualificationList.map(item => item.title)]
  222. },
  223. },
  224. onLoad(options) {
  225. // 如果是编辑模式,加载已有数据
  226. if (options.edit && options.data) {
  227. this.loadExistingData(JSON.parse(decodeURIComponent(options.data)));
  228. }
  229. },
  230. created() {
  231. this.getAddressData()
  232. // 调试store数据
  233. console.log('Store careerList:', this.$store.state.careerList)
  234. console.log('Store qualificationList:', this.$store.state.qualificationList)
  235. },
  236. methods: {
  237. // 加载已有数据(编辑模式)
  238. loadExistingData(data) {
  239. this.formData = {
  240. name: data.name || '李双欢',
  241. phone: data.phone || '15478451233',
  242. sex: data.sex || '男',
  243. // sexText: data.sex || '男',
  244. area: data.area || '湖南省长沙市区',
  245. areaText: data.area || '湖南省长沙市区',
  246. address: data.address || '阳光小区45栋二单元1203',
  247. career: data.career || '专业技术人员',
  248. // careerText: data.career || '专业技术人员',
  249. qualifications: data.qualifications || '本科',
  250. // qualificationsText: data.qualifications || '本科',
  251. skill: data.skill || '计算机、跑步'
  252. };
  253. this.emergencyData = {
  254. emergencyName: data.emergencyName || '李四',
  255. emergencyPhone: data.emergencyPhone || '14563236320'
  256. };
  257. },
  258. // 初始化地区数据
  259. getAddressData() {
  260. console.log('开始加载地区数据');
  261. try {
  262. // 直接使用导入的地区数据(已简化,只包含name字段)
  263. this.provinces = chinaRegions;
  264. // console.log('成功加载地区数据,省份数量:', this.provinces.length);
  265. this.handlePickValueDefault();
  266. // uni.showToast({
  267. // title: '地区数据加载成功',
  268. // icon: 'success'
  269. // });
  270. } catch (error) {
  271. // console.error('加载地区数据失败:', error);
  272. // uni.showToast({
  273. // title: '地区数据加载失败',
  274. // icon: 'error'
  275. // });
  276. }
  277. },
  278. handlePickValueDefault() {
  279. if (this.provinces.length > 0) {
  280. // 设置省(默认选择第一个省份)
  281. this.pickerValue[0] = 0;
  282. // 设置市(默认选择第一个市)
  283. this.citys = this.provinces[0]?.children || [];
  284. this.pickerValue[1] = 0;
  285. // 设置区(默认选择第一个区)
  286. this.areas = this.citys[0]?.children || [];
  287. this.pickerValue[2] = 0;
  288. console.log('初始化地区数据:', {
  289. provinces: this.provinces.length,
  290. citys: this.citys.length,
  291. areas: this.areas.length
  292. });
  293. }
  294. },
  295. // 打开性别选择器
  296. openGenderPicker() {
  297. // console.log('我点击了性别选择去');
  298. this.$refs.genderPicker.open();
  299. },
  300. // 打开地区选择器
  301. openRegionPicker() {
  302. this.$refs.regionPicker.open();
  303. },
  304. // 打开职业选择器
  305. openProfessionPicker() {
  306. this.$refs.professionPicker.open();
  307. },
  308. // 打开学历选择器
  309. openEducationPicker() {
  310. this.$refs.educationPicker.open();
  311. },
  312. // 性别选择确认
  313. onGenderConfirm(value) {
  314. this.formData.sex = value.value[0];
  315. },
  316. // 地区选择变化(三级联动)
  317. onAddressChange(e) {
  318. console.log('地区选择变化:', e);
  319. const { columnIndex, index, value } = e;
  320. if (columnIndex === 0) {
  321. // 选择省份时,更新市级数据
  322. this.citys = this.provinces[index]?.children || [];
  323. this.areas = this.citys[0]?.children || [];
  324. this.pickerValue = [index, 0, 0];
  325. } else if (columnIndex === 1) {
  326. // 选择市时,更新区级数据
  327. this.areas = this.citys[index]?.children || [];
  328. this.pickerValue[1] = index;
  329. this.pickerValue[2] = 0;
  330. } else if (columnIndex === 2) {
  331. // 选择区
  332. this.pickerValue[2] = index;
  333. }
  334. },
  335. // 地区选择确认
  336. onAddressConfirm(e) {
  337. console.log('确认选择的地区:', e);
  338. if (e.value && e.value.length >= 3) {
  339. const selectedArea = `${e.value[0].name}/${e.value[1].name}/${e.value[2].name}`;
  340. this.formData.area = selectedArea; // 给area字段赋值用于表单验证
  341. uni.showToast({
  342. icon: 'success',
  343. title: '地区选择成功'
  344. });
  345. } else {
  346. uni.showToast({
  347. icon: 'none',
  348. title: '请选择完整的省市区信息'
  349. });
  350. }
  351. },
  352. // 职业选择确认
  353. onProfessionConfirm(value) {
  354. console.log('职业选择确认:', value.value[0]);
  355. this.formData.career = value.value[0];
  356. },
  357. // 学历选择确认
  358. onEducationConfirm(value) {
  359. console.log('学历选择确认:', value.value[0]);
  360. this.formData.qualifications = value.value[0];
  361. },
  362. // 提交申请
  363. async submitApplication() {
  364. try {
  365. // 验证主表单
  366. const valid = await this.$refs.form.validate();
  367. if (!valid) return;
  368. // 验证紧急联系人信息
  369. if (!this.emergencyData.emergencyName || !this.emergencyData.emergencyPhone) {
  370. uni.showToast({
  371. title: '请填写紧急联系人信息',
  372. icon: 'none'
  373. });
  374. return;
  375. }
  376. this.submitting = true;
  377. // 模拟提交
  378. await this.submitVolunteerApplication();
  379. } catch (error) {
  380. console.error('提交失败:', error);
  381. uni.showToast({
  382. title: '提交失败,请重试',
  383. icon: 'none'
  384. });
  385. } finally {
  386. this.submitting = false;
  387. }
  388. },
  389. // 提交志愿者申请API
  390. async submitVolunteerApplication() {
  391. // 要求通过title获取id
  392. this.formData.career = this.$store.state.careerList.find(item => item.title === this.formData.career).id
  393. this.formData.qualifications = this.$store.state.qualificationList.find(item => item.title === this.formData.qualifications).id
  394. const res = await this.$api.home.applyVolunteer({...this.formData, ...this.emergencyData})
  395. if (res.code === 200){
  396. uni.showToast({
  397. title: `${res.message}`,
  398. icon: 'none'
  399. })
  400. setTimeout(() => {
  401. uni.navigateBack();
  402. }, 1000);
  403. }else {
  404. uni.showToast({
  405. title: res.msg,
  406. icon: 'none'
  407. })
  408. }
  409. }
  410. }
  411. }
  412. </script>
  413. <style lang="scss" scoped>
  414. // @import '@/uni.scss';
  415. .volunteer-apply-page {
  416. min-height: 100vh;
  417. background-color: #f5f5f5;
  418. }
  419. .header-section {
  420. position: relative;
  421. width: 96%;
  422. height: 290rpx;
  423. margin: 25rpx auto;
  424. .bg-image {
  425. width: 100%;
  426. height: 100%;
  427. }
  428. }
  429. .tip-section {
  430. display: flex;
  431. align-items: center;
  432. padding: 30rpx;
  433. background-color: #fff;
  434. margin: 20rpx 30rpx;
  435. border-radius: 16rpx;
  436. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  437. .tip-text {
  438. margin-left: 16rpx;
  439. font-size: 28rpx;
  440. color: #666;
  441. line-height: 1.5;
  442. }
  443. }
  444. .form-section {
  445. background-color: #fff;
  446. margin: 20rpx 30rpx;
  447. border-radius: 16rpx;
  448. padding: 40rpx 30rpx;
  449. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  450. }
  451. .emergency-section {
  452. margin-top: 40rpx;
  453. padding-top: 40rpx;
  454. border-top: 1rpx solid #f0f0f0;
  455. .section-title {
  456. font-size: 32rpx;
  457. font-weight: bold;
  458. color: #333;
  459. margin-bottom: 30rpx;
  460. }
  461. }
  462. .submit-section {
  463. padding: 40rpx 30rpx;
  464. padding-bottom: 60rpx;
  465. }
  466. // 覆盖uvUI样式
  467. :deep(.uv-form-item__body__right__content__input) {
  468. font-size: 28rpx !important;
  469. }
  470. :deep(.uv-form-item__body__left__text) {
  471. font-size: 28rpx !important;
  472. color: #333 !important;
  473. }
  474. :deep(.uv-input__content__field-wrapper__field) {
  475. font-size: 28rpx !important;
  476. }
  477. :deep(.uv-textarea__content__field) {
  478. font-size: 28rpx !important;
  479. }
  480. </style>