register.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. import { enroll,smsSend,enrollDetail } from '../../api/other';
  2. import { FETCH_AND_FORMAT_USER_INFO } from '../../utils/util.js'
  3. import { uploadImage } from '../../utils/upload.js';
  4. import {BASE_URL} from '../../utils/request';
  5. const app = getApp();
  6. Page({
  7. data: {
  8. formData: {
  9. phone: '',
  10. captcha: '',
  11. nickname: '',
  12. gender: '', // '女' 或 '男'
  13. race_number: '', // 身份证号
  14. // competition_no: '', // 比赛ID
  15. competition_image: '' // 上传的图片路径
  16. },
  17. phoneError: '',
  18. raceNumberError:'',
  19. genders: ['女', '男'],
  20. showPicker: false,
  21. fileList: [],
  22. checked: false,
  23. showRegistrationSuccess: false,
  24. canSubmit: false, // 按钮是否可点击
  25. showAgreementModal:false,
  26. agreementContent:'',
  27. agreementTitle:'',
  28. codeText: '获取验证码',
  29. codeDisabled: false,
  30. timer: null,
  31. countdown: 60,
  32. couponInfo:{},
  33. filePath: '', // 上传成功的文件路径
  34. fileType: '', // image / pdf
  35. baseUrl:BASE_URL,
  36. isEdit: false,// 是否已有报名信息
  37. },
  38. async onLoad(){
  39. const res = await enrollDetail();
  40. if (res.code == 200 && res.data) {
  41. let { phone, nickname, gender, race_number, competition_image } = res.data;
  42. this.setData({
  43. formData: {
  44. phone,
  45. nickname,
  46. race_number,
  47. competition_image,
  48. gender: gender == 0 ? '女' : '男',
  49. },
  50. filePath:BASE_URL + competition_image,
  51. fileType:this.getFileType(competition_image),
  52. isEdit: true
  53. });
  54. }
  55. },
  56. getFileType(url) {
  57. const extension = url.split('.').pop().toLowerCase();
  58. if (['jpg','jpeg','png','gif','webp','bmp'].includes(extension)) {
  59. return 'image';
  60. } else if (extension === 'pdf') {
  61. return 'pdf';
  62. }
  63. return 'unknown';
  64. },
  65. onShowPicker() {
  66. this.setData({ showPicker: true });
  67. },
  68. onCancel() {
  69. this.setData({ showPicker: false });
  70. },
  71. // 性别确定
  72. onConfirm(event) {
  73. const { value } = event.detail;
  74. this.setData({
  75. formData: {
  76. ...this.data.formData,
  77. gender: value
  78. },
  79. showPicker: false
  80. }, () => this.checkFormValid());
  81. },
  82. // 点击上传区域
  83. chooseFile() {
  84. wx.showActionSheet({
  85. itemList: ['图片', 'PDF'],
  86. success: res => {
  87. if (res.tapIndex === 0) {
  88. this.chooseImage();
  89. } else {
  90. this.choosePdf();
  91. }
  92. }
  93. });
  94. },
  95. // 选择图片
  96. chooseImage() {
  97. wx.chooseImage({
  98. count: 1,
  99. sizeType: ['original', 'compressed'],
  100. sourceType: ['album', 'camera'],
  101. success: res => {
  102. const path = res.tempFilePaths[0];
  103. this.uploadFile(path, 'image');
  104. }
  105. });
  106. },
  107. // 选择 PDF
  108. choosePdf() {
  109. wx.chooseMessageFile({
  110. count: 1,
  111. type: 'file',
  112. success: res => {
  113. const file = res.tempFiles[0];
  114. if (file.name.endsWith('.pdf')) {
  115. this.uploadFile(file.path, 'pdf');
  116. } else {
  117. wx.showToast({ title: '请选择 PDF 文件', icon: 'none' });
  118. }
  119. }
  120. });
  121. },
  122. // 上传文件
  123. async uploadFile(path, type) {
  124. if (!path) {
  125. wx.showToast({ title: '文件路径错误', icon: 'none' });
  126. return;
  127. }
  128. try {
  129. const res = await uploadImage(path);
  130. console.log('上传成功:', res);
  131. this.setData({
  132. filePath: res.url,
  133. fileType: type,
  134. "formData.competition_image": res.path
  135. }, () => this.checkFormValid());
  136. } catch (err) {
  137. console.error('上传失败:', err);
  138. }
  139. },
  140. // 删除文件
  141. removeFile() {
  142. this.setData({
  143. filePath: '',
  144. fileType: '',
  145. "formData.competition_image": ''
  146. },() => this.checkFormValid());
  147. },
  148. // 输入框数据绑定
  149. onInput(e) {
  150. console.log(e)
  151. const field = e.currentTarget.dataset.field;
  152. const value = e.detail;
  153. console.log(value)
  154. // 手机号单独做校验
  155. if (field === 'phone') {
  156. const regPhone = /^1[3-9]\d{9}$/;
  157. if (value && !regPhone.test(value)) {
  158. this.setData({ phoneError: '手机号格式不正确' });
  159. }else{
  160. this.setData({ phoneError: '' });
  161. }
  162. }
  163. if (field === 'race_number') {
  164. const regIdCard = /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;
  165. if (value && !regIdCard.test(value)) {
  166. this.setData({ raceNumberError: '身份证号格式不正确' });
  167. }else{
  168. this.setData({ raceNumberError: '' });
  169. }
  170. }
  171. this.setData({
  172. formData: { ...this.data.formData, [field]: value }
  173. }, () => this.checkFormValid());
  174. },
  175. // 勾选协议
  176. onCheckbox(event) {
  177. this.setData({ checked: event.detail }, () => this.checkFormValid());
  178. },
  179. // 校验表单是否可提交
  180. checkFormValid() {
  181. const { phone, captcha, nickname, gender, race_number, competition_image } = this.data.formData;
  182. const { isEdit, checked, raceNumberError, phoneError } = this.data;
  183. let valid = false;
  184. if (isEdit) {
  185. valid = phone && nickname && gender && race_number && competition_image && checked && !raceNumberError && !phoneError;
  186. } else {
  187. valid = phone && captcha && nickname && gender && race_number && competition_image && checked && !raceNumberError && !phoneError;
  188. }
  189. this.setData({ canSubmit: valid });
  190. },
  191. // 获取验证码
  192. async getCode() {
  193. if(this.data.codeDisabled) return;
  194. const phone = this.data.formData.phone;
  195. if (!phone) {
  196. wx.showToast({
  197. title: '请输入手机号',
  198. icon: 'none'
  199. });
  200. return;
  201. }
  202. if (!/^1[3-9]\d{9}$/.test(phone)) {
  203. wx.showToast({
  204. title: '手机号格式不正确',
  205. icon: 'none'
  206. });
  207. return;
  208. }
  209. // 禁用按钮
  210. this.setData({ codeDisabled: true });
  211. const res = await smsSend({phone:this.data.formData.phone});
  212. if (res.code == 200) {
  213. wx.showToast({ title: '验证码已发送', icon: 'none' });
  214. this.startCountdown();
  215. } else {
  216. wx.showToast({ title: res.message || '发送失败', icon: 'none' });
  217. this.setData({ codeDisabled: false });
  218. }
  219. },
  220. // 提交报名
  221. async onSubmit() {
  222. this.checkFormValid();
  223. if (!this.data.canSubmit) return;
  224. const payload = {
  225. ...this.data.formData,
  226. gender: this.data.formData.gender === '女' ? 0 : 1
  227. };
  228. const res = await enroll(payload);
  229. if (res.code === 200) {
  230. await FETCH_AND_FORMAT_USER_INFO();
  231. if (!this.data.isEdit) {
  232. this.setData({
  233. couponInfo: res.data[0],
  234. showRegistrationSuccess: true
  235. });
  236. } else {
  237. wx.showToast({ title: '修改成功', icon: 'none' });
  238. wx.navigateBack({ delta: 1 });
  239. }
  240. } else {
  241. wx.showToast({ title: res.message || '报名失败', icon: 'none', duration: 2000 });
  242. }
  243. },
  244. // 点击协议文字显示弹窗
  245. showAgreement(e) {
  246. const type = e.currentTarget.dataset.type;
  247. const dataInfo = app.globalData.programConfig;
  248. this.setData({
  249. showAgreementModal: true,
  250. agreementContent: type == 'liability'?dataInfo.disclaimer : dataInfo.privacy_policy,
  251. agreementTitle:type == 'liability'?'活动须知' : '隐私政策'
  252. });
  253. },
  254. closeAgreementModal() {
  255. this.setData({ showAgreementModal: false });
  256. },
  257. onReceive() {
  258. this.setData({ showRegistrationSuccess: false });
  259. wx.navigateBack({ delta: 1 });
  260. },
  261. //预览图片
  262. previewImage(e){
  263. const current = e.currentTarget.dataset.src;
  264. wx.previewImage({
  265. current,
  266. urls: [current]
  267. });
  268. },
  269. startCountdown() {
  270. let countdown = this.data.countdown;
  271. this.setData({ codeText: `${countdown}s` });
  272. if (this.data.timer) clearInterval(this.data.timer);
  273. this.data.timer = setInterval(() => {
  274. countdown -= 1;
  275. if (countdown <= 0) {
  276. clearInterval(this.data.timer);
  277. this.setData({ codeText: '获取验证码', codeDisabled: false, countdown: 60 });
  278. } else {
  279. this.setData({ codeText: `${countdown}s`, countdown });
  280. }
  281. }, 1000);
  282. },
  283. onUnload() {
  284. if (this.data.timer) clearInterval(this.data.timer);
  285. }
  286. });