register.js 8.1 KB

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