Commit f566491d5b27e0f5446937663c279ab6a5e8e107
1 parent
9b4afe08
最新
Showing
10 changed files
with
1247 additions
and
45 deletions
绿纤uni-app/pages/addServiceLog/addServiceLogcopy.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="container"> | ||
| 3 | + <!-- 会员信息卡片 --> | ||
| 4 | + <view class="member-card"> | ||
| 5 | + <view class="member-info"> | ||
| 6 | + <view class="member-avatar">👤</view> | ||
| 7 | + <view class="member-details"> | ||
| 8 | + <view class="member-name">{{ memberName }}</view> | ||
| 9 | + <view class="member-id">消费记录ID: {{ consumeId }}</view> | ||
| 10 | + </view> | ||
| 11 | + </view> | ||
| 12 | + </view> | ||
| 13 | + | ||
| 14 | + <!-- 表单卡片 --> | ||
| 15 | + <view class="form-card"> | ||
| 16 | + <view class="form-content"> | ||
| 17 | + <form @submit="handleFormSubmit"> | ||
| 18 | + <!-- 使用前图片 --> | ||
| 19 | + <view class="form-group"> | ||
| 20 | + <text class="form-label">使用前图片</text> | ||
| 21 | + <view class="input-wrapper"> | ||
| 22 | + <view class="file-upload-area" @tap.stop="chooseFile('before')"> | ||
| 23 | + <view class="file-upload-text"> | ||
| 24 | + <text class="file-upload-icon">📷</text> | ||
| 25 | + <text>点击选择使用前图片</text> | ||
| 26 | + </view> | ||
| 27 | + <view class="file-list"> | ||
| 28 | + <view v-for="(file, index) in beforeImages" :key="index" class="file-item"> | ||
| 29 | + <view class="file-info"> | ||
| 30 | + <text class="file-icon">🖼️</text> | ||
| 31 | + <text class="file-name">{{ file.name }}</text> | ||
| 32 | + </view> | ||
| 33 | + <view class="file-actions"> | ||
| 34 | + <view v-if="file.status === 'uploading'" class="file-status uploading">上传中...</view> | ||
| 35 | + <view v-else-if="file.status === 'success'" class="file-status success">✓ 已上传</view> | ||
| 36 | + <view v-else-if="file.status === 'error'" class="file-status error">✗ 上传失败</view> | ||
| 37 | + <button v-if="file.status === 'success'" class="btn-error" @click.stop="removeFile('before', index)">删除</button> | ||
| 38 | + </view> | ||
| 39 | + </view> | ||
| 40 | + </view> | ||
| 41 | + </view> | ||
| 42 | + </view> | ||
| 43 | + </view> | ||
| 44 | + | ||
| 45 | + <!-- 使用后图片 --> | ||
| 46 | + <view class="form-group"> | ||
| 47 | + <text class="form-label">使用后图片</text> | ||
| 48 | + <view class="input-wrapper"> | ||
| 49 | + <view class="file-upload-area" @tap.stop="chooseFile('after')"> | ||
| 50 | + <view class="file-upload-text"> | ||
| 51 | + <text class="file-upload-icon">📷</text> | ||
| 52 | + <text>点击选择使用后图片</text> | ||
| 53 | + </view> | ||
| 54 | + <view class="file-list"> | ||
| 55 | + <view v-for="(file, index) in afterImages" :key="index" class="file-item"> | ||
| 56 | + <view class="file-info"> | ||
| 57 | + <text class="file-icon">🖼️</text> | ||
| 58 | + <text class="file-name">{{ file.name }}</text> | ||
| 59 | + </view> | ||
| 60 | + <view class="file-actions"> | ||
| 61 | + <view v-if="file.status === 'uploading'" class="file-status uploading">上传中...</view> | ||
| 62 | + <view v-else-if="file.status === 'success'" class="file-status success">✓ 已上传</view> | ||
| 63 | + <view v-else-if="file.status === 'error'" class="file-status error">✗ 上传失败</view> | ||
| 64 | + <button v-if="file.status === 'success'" class="btn-error" @click.stop="removeFile('after', index)">删除</button> | ||
| 65 | + </view> | ||
| 66 | + </view> | ||
| 67 | + </view> | ||
| 68 | + </view> | ||
| 69 | + </view> | ||
| 70 | + </view> | ||
| 71 | + <!-- 语音备注(H5 环境自动隐藏,仅小程序 / App 生效) --> | ||
| 72 | + <view class="form-group" v-if="enableVoice"> | ||
| 73 | + <text class="form-label">语音备注</text> | ||
| 74 | + <view class="voice-card"> | ||
| 75 | + <view class="voice-main"> | ||
| 76 | + <view class="voice-record-btn" :class="{ recording: voiceNote.status === 'recording' }" @tap="toggleRecord"> | ||
| 77 | + <!-- <text class="voice-record-icon">🎙️</text> --> | ||
| 78 | + <u-icon name="mic" color="#fff" size="28"></u-icon> | ||
| 79 | + </view> | ||
| 80 | + <view class="voice-info"> | ||
| 81 | + <view class="voice-status-text"> | ||
| 82 | + {{ voiceStatusText }} | ||
| 83 | + </view> | ||
| 84 | + <view class="voice-duration" v-if="voiceNote.duration"> | ||
| 85 | + {{ formatVoiceDuration(voiceNote.duration) }} | ||
| 86 | + </view> | ||
| 87 | + </view> | ||
| 88 | + </view> | ||
| 89 | + <view class="voice-actions" v-if="voiceNote.url"> | ||
| 90 | + <view class="voice-wave" :class="{ playing: voiceNote.isPlaying }"> | ||
| 91 | + <view class="wave-bar" v-for="n in 5" :key="n"></view> | ||
| 92 | + </view> | ||
| 93 | + <button class="btn-plain" @tap.stop="togglePlayVoice"> | ||
| 94 | + {{ voiceNote.isPlaying ? '暂停播放' : '播放语音' }} | ||
| 95 | + </button> | ||
| 96 | + <button class="btn-error" @tap.stop="removeVoice">删除</button> | ||
| 97 | + </view> | ||
| 98 | + </view> | ||
| 99 | + </view> | ||
| 100 | + | ||
| 101 | + <view class="form-group" v-else> | ||
| 102 | + <text class="form-label">语音备注</text> | ||
| 103 | + <view class="voice-card voice-card--disabled"> | ||
| 104 | + <view class="voice-main"> | ||
| 105 | + <view class="voice-record-btn"> | ||
| 106 | + <text class="voice-record-icon">🎙️</text> | ||
| 107 | + </view> | ||
| 108 | + <view class="voice-info"> | ||
| 109 | + <view class="voice-status-text"> | ||
| 110 | + 当前 H5 环境暂不支持录音,请在小程序或 App 中使用语音备注。 | ||
| 111 | + </view> | ||
| 112 | + </view> | ||
| 113 | + </view> | ||
| 114 | + </view> | ||
| 115 | + </view> | ||
| 116 | + <!-- 反馈备注 --> | ||
| 117 | + <view class="form-group"> | ||
| 118 | + <text class="form-label">反馈备注</text> | ||
| 119 | + <view class="input-wrapper"> | ||
| 120 | + <textarea v-model="formData.remark" placeholder="请输入反馈备注" :maxlength="500" :count="true" | ||
| 121 | + class="textarea-input" /> | ||
| 122 | + </view> | ||
| 123 | + </view> | ||
| 124 | + <!-- 科技部备注 --> | ||
| 125 | + <view class="form-group"> | ||
| 126 | + <text class="form-label">科技部备注</text> | ||
| 127 | + <view class="input-wrapper"> | ||
| 128 | + <textarea v-model="formData.kjbRemark" placeholder="请输入科技部备注" :maxlength="500" :count="true" | ||
| 129 | + class="textarea-input" /> | ||
| 130 | + </view> | ||
| 131 | + </view> | ||
| 132 | + | ||
| 133 | + <!-- 提交按钮 --> | ||
| 134 | + <view class="btn-group"> | ||
| 135 | + <button type="submit" class="btn btn-primary" :style="{opacity: isSubmitting?0.5:1}" @tap="isSubmitting?null:submitServiceLog()"> | ||
| 136 | + {{ isSubmitting?(isEditMode?'更新中...':'提交中...'):(isEditMode?'更新服务日志':'提交服务日志') }} | ||
| 137 | + </button> | ||
| 138 | + </view> | ||
| 139 | + </form> | ||
| 140 | + </view> | ||
| 141 | + </view> | ||
| 142 | + </view> | ||
| 143 | +</template> | ||
| 144 | + | ||
| 145 | +<script> | ||
| 146 | + import lxApi from '@/apis/modules/lx.js' | ||
| 147 | + import config from '@/common/config.js' | ||
| 148 | + | ||
| 149 | + export default { | ||
| 150 | + data() { | ||
| 151 | + return { | ||
| 152 | + consumeId: '', | ||
| 153 | + memberName: '', | ||
| 154 | + logId: '', | ||
| 155 | + isEditMode: false, | ||
| 156 | + isSubmitting: false, | ||
| 157 | + baseUrl: config.getImgBaseUrl(), | ||
| 158 | + formData: { | ||
| 159 | + remark: '', | ||
| 160 | + kjbRemark: '' | ||
| 161 | + }, | ||
| 162 | + beforeImages: [], | ||
| 163 | + afterImages: [], | ||
| 164 | + enableVoice: true, | ||
| 165 | + voiceNote: { | ||
| 166 | + fileId: '', | ||
| 167 | + url: '', | ||
| 168 | + duration: 0, | ||
| 169 | + status: 'idle', // idle | recording | recorded | processing | ||
| 170 | + uploading: false, | ||
| 171 | + isPlaying: false | ||
| 172 | + }, | ||
| 173 | + recorderInited: false | ||
| 174 | + } | ||
| 175 | + }, | ||
| 176 | + onReady() { | ||
| 177 | + // #ifdef H5 | ||
| 178 | + this.enableVoice = false | ||
| 179 | + // #endif | ||
| 180 | + // #ifndef H5 | ||
| 181 | + this.initRecorder() | ||
| 182 | + // #endif | ||
| 183 | + }, | ||
| 184 | + onLoad(options) { | ||
| 185 | + // 获取传递的参数 | ||
| 186 | + this.consumeId = options.consumeId || '' | ||
| 187 | + this.memberName = decodeURIComponent(options.memberName || '未知会员') | ||
| 188 | + this.logId = options.logId || '' | ||
| 189 | + this.isEditMode = options.mode === 'edit' | ||
| 190 | + | ||
| 191 | + // 如果是编辑模式,加载现有数据 | ||
| 192 | + if (this.isEditMode && this.logId) { | ||
| 193 | + this.loadServiceLogDetail() | ||
| 194 | + } | ||
| 195 | + }, | ||
| 196 | + computed: { | ||
| 197 | + voiceStatusText() { | ||
| 198 | + if (this.voiceNote.status === 'recording') { | ||
| 199 | + return '正在录音,再次点击即可结束' | ||
| 200 | + } | ||
| 201 | + if (this.voiceNote.status === 'processing' || this.voiceNote.uploading) { | ||
| 202 | + return '语音处理中 / 上传中...' | ||
| 203 | + } | ||
| 204 | + if (this.voiceNote.url) { | ||
| 205 | + return '已录制语音,可点击播放或重新录制' | ||
| 206 | + } | ||
| 207 | + return '点击麦克风图标开始录音' | ||
| 208 | + } | ||
| 209 | + }, | ||
| 210 | + methods: { | ||
| 211 | + // 返回上一页 | ||
| 212 | + goBack() { | ||
| 213 | + uni.navigateBack({ | ||
| 214 | + delta: 1 | ||
| 215 | + }) | ||
| 216 | + }, | ||
| 217 | + | ||
| 218 | + // 加载服务日志详情(编辑模式) | ||
| 219 | + async loadServiceLogDetail() { | ||
| 220 | + try { | ||
| 221 | + uni.showLoading({ | ||
| 222 | + title: '加载中...' | ||
| 223 | + }) | ||
| 224 | + | ||
| 225 | + const result = await lxApi.getServiceLogDetail(this.logId) | ||
| 226 | + uni.hideLoading() | ||
| 227 | + | ||
| 228 | + if (result.code === 200 && result.data) { | ||
| 229 | + const log = result.data | ||
| 230 | + | ||
| 231 | + // 填充表单数据 | ||
| 232 | + this.formData.remark = log.remark || '' | ||
| 233 | + this.formData.kjbRemark = log.kjbRemark || '' | ||
| 234 | + | ||
| 235 | + // 加载图片数据 | ||
| 236 | + this.beforeImages = this.parseImageJson(log.beforeImage) | ||
| 237 | + this.afterImages = this.parseImageJson(log.afterImage) | ||
| 238 | + | ||
| 239 | + // 加载语音备注数据(如果后端已支持) | ||
| 240 | + if (log.voiceUrl) { | ||
| 241 | + this.voiceNote.url = log.voiceUrl | ||
| 242 | + this.voiceNote.duration = log.voiceDuration || 0 | ||
| 243 | + this.voiceNote.fileId = log.voiceFileId || '' | ||
| 244 | + this.voiceNote.status = 'recorded' | ||
| 245 | + } | ||
| 246 | + } else { | ||
| 247 | + uni.showToast({ | ||
| 248 | + title: result.msg || '加载失败', | ||
| 249 | + icon: 'none' | ||
| 250 | + }) | ||
| 251 | + } | ||
| 252 | + } catch (error) { | ||
| 253 | + uni.hideLoading() | ||
| 254 | + console.error('加载服务日志详情失败:', error) | ||
| 255 | + uni.showToast({ | ||
| 256 | + title: '加载失败,请稍后重试', | ||
| 257 | + icon: 'none' | ||
| 258 | + }) | ||
| 259 | + } | ||
| 260 | + }, | ||
| 261 | + | ||
| 262 | + // 解析图片JSON字符串 | ||
| 263 | + parseImageJson(imageJson) { | ||
| 264 | + try { | ||
| 265 | + if (!imageJson) return [] | ||
| 266 | + const images = JSON.parse(imageJson) | ||
| 267 | + // 将现有图片转换为文件列表格式 | ||
| 268 | + return images.map((image, index) => ({ | ||
| 269 | + id: `existing_${Date.now()}_${index}`, | ||
| 270 | + name: image.name || image.fileId || `图片${index + 1}`, | ||
| 271 | + size: 0, | ||
| 272 | + type: 'image/jpeg', | ||
| 273 | + status: 'success', | ||
| 274 | + url: image.url || '', | ||
| 275 | + fileId: image.fileId || image.name || '' | ||
| 276 | + })) | ||
| 277 | + } catch (error) { | ||
| 278 | + console.error('解析图片JSON失败:', error) | ||
| 279 | + return [] | ||
| 280 | + } | ||
| 281 | + }, | ||
| 282 | + | ||
| 283 | + // 选择文件 | ||
| 284 | + chooseFile(type) { | ||
| 285 | + uni.chooseImage({ | ||
| 286 | + count: 9, | ||
| 287 | + success: (res) => { | ||
| 288 | + // 将tempFilePaths转换为tempFiles格式 | ||
| 289 | + const tempFiles = res.tempFilePaths.map((path, index) => ({ | ||
| 290 | + path: path, | ||
| 291 | + tempFilePath: path, | ||
| 292 | + size: res.tempFiles ? res.tempFiles[index].size : 0, | ||
| 293 | + name: `image_${Date.now()}_${index}.jpg`, | ||
| 294 | + type: 'image/jpeg' | ||
| 295 | + })); | ||
| 296 | + this.handleFileSelect(tempFiles, type); | ||
| 297 | + } | ||
| 298 | + }); | ||
| 299 | + }, | ||
| 300 | + | ||
| 301 | + // 处理文件选择 | ||
| 302 | + async handleFileSelect(files, type) { | ||
| 303 | + for (let i = 0; i < files.length; i++) { | ||
| 304 | + const file = files[i]; | ||
| 305 | + | ||
| 306 | + // 验证文件大小 (限制为10MB) | ||
| 307 | + if (file.size > 10 * 1024 * 1024) { | ||
| 308 | + uni.showToast({ | ||
| 309 | + title: `文件 ${file.name} 大小超过10MB限制`, | ||
| 310 | + icon: 'none' | ||
| 311 | + }); | ||
| 312 | + continue; | ||
| 313 | + } | ||
| 314 | + | ||
| 315 | + // 上传文件 | ||
| 316 | + await this.uploadSingleFile(file, type); | ||
| 317 | + } | ||
| 318 | + }, | ||
| 319 | + | ||
| 320 | + // 上传单个文件 | ||
| 321 | + async uploadSingleFile(file, type) { | ||
| 322 | + const fileId = `file_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; | ||
| 323 | + | ||
| 324 | + // 添加到文件列表显示 | ||
| 325 | + this.addFileToList(file, fileId, 'uploading', type); | ||
| 326 | + | ||
| 327 | + try { | ||
| 328 | + const result = await lxApi.uploadFile(file); | ||
| 329 | + | ||
| 330 | + if (result.code === 200 && result.data) { | ||
| 331 | + // 更新文件状态为成功 | ||
| 332 | + this.updateFileStatus(fileId, 'success', type, result.data); | ||
| 333 | + | ||
| 334 | + uni.showToast({ | ||
| 335 | + title: '文件上传成功', | ||
| 336 | + icon: 'success' | ||
| 337 | + }); | ||
| 338 | + } else { | ||
| 339 | + throw new Error(result.msg || '上传失败'); | ||
| 340 | + } | ||
| 341 | + } catch (error) { | ||
| 342 | + console.error('文件上传失败:', error); | ||
| 343 | + this.updateFileStatus(fileId, 'error', type); | ||
| 344 | + uni.showToast({ | ||
| 345 | + title: `文件 ${file.name} 上传失败`, | ||
| 346 | + icon: 'none' | ||
| 347 | + }); | ||
| 348 | + } | ||
| 349 | + }, | ||
| 350 | + | ||
| 351 | + // 添加文件到列表显示 | ||
| 352 | + addFileToList(file, fileId, status, type) { | ||
| 353 | + const fileItem = { | ||
| 354 | + id: fileId, | ||
| 355 | + name: file.name, | ||
| 356 | + size: file.size, | ||
| 357 | + type: file.type, | ||
| 358 | + status: status, | ||
| 359 | + url: '', | ||
| 360 | + fileId: '' | ||
| 361 | + }; | ||
| 362 | + | ||
| 363 | + if (type === 'before') { | ||
| 364 | + this.beforeImages.push(fileItem); | ||
| 365 | + } else { | ||
| 366 | + this.afterImages.push(fileItem); | ||
| 367 | + } | ||
| 368 | + }, | ||
| 369 | + | ||
| 370 | + // 更新文件状态 | ||
| 371 | + updateFileStatus(fileId, status, type, uploadData = null) { | ||
| 372 | + const fileList = type === 'before' ? this.beforeImages : this.afterImages; | ||
| 373 | + const fileIndex = fileList.findIndex(file => file.id === fileId); | ||
| 374 | + | ||
| 375 | + if (fileIndex !== -1) { | ||
| 376 | + fileList[fileIndex].status = status; | ||
| 377 | + if (uploadData) { | ||
| 378 | + fileList[fileIndex].url = uploadData.url; | ||
| 379 | + fileList[fileIndex].fileId = uploadData.name; | ||
| 380 | + fileList[fileIndex].name = uploadData.name; | ||
| 381 | + } | ||
| 382 | + } | ||
| 383 | + }, | ||
| 384 | + | ||
| 385 | + // 删除文件 | ||
| 386 | + removeFile(type, index) { | ||
| 387 | + if (type === 'before') { | ||
| 388 | + this.beforeImages.splice(index, 1); | ||
| 389 | + } else { | ||
| 390 | + this.afterImages.splice(index, 1); | ||
| 391 | + } | ||
| 392 | + }, | ||
| 393 | + | ||
| 394 | + // 表单提交 | ||
| 395 | + handleFormSubmit(event) { | ||
| 396 | + event.preventDefault(); | ||
| 397 | + this.submitServiceLog(); | ||
| 398 | + }, | ||
| 399 | + | ||
| 400 | + // 提交服务日志 | ||
| 401 | + async submitServiceLog() { | ||
| 402 | + try { | ||
| 403 | + // 验证表单 | ||
| 404 | + if (!this.formData.remark.trim()) { | ||
| 405 | + uni.showToast({ | ||
| 406 | + title: '请输入反馈备注', | ||
| 407 | + icon: 'none' | ||
| 408 | + }); | ||
| 409 | + return; | ||
| 410 | + } | ||
| 411 | + | ||
| 412 | + // 检查是否有图片/语音正在上传 | ||
| 413 | + const uploadingBefore = this.beforeImages.some(file => file.status === 'uploading'); | ||
| 414 | + const uploadingAfter = this.afterImages.some(file => file.status === 'uploading'); | ||
| 415 | + const uploadingVoice = this.voiceNote.uploading; | ||
| 416 | + | ||
| 417 | + if (uploadingBefore || uploadingAfter || uploadingVoice) { | ||
| 418 | + uni.showToast({ | ||
| 419 | + title: '请等待图片/语音上传完成', | ||
| 420 | + icon: 'none' | ||
| 421 | + }); | ||
| 422 | + return; | ||
| 423 | + } | ||
| 424 | + | ||
| 425 | + // 准备提交数据 | ||
| 426 | + const submitData = { | ||
| 427 | + consumeId: this.consumeId, | ||
| 428 | + beforeImage: JSON.stringify(this.beforeImages.filter(file => file.status === 'success').map(file => ({ | ||
| 429 | + name: file.name, | ||
| 430 | + url: file.url, | ||
| 431 | + fileId: file.fileId | ||
| 432 | + }))), | ||
| 433 | + afterImage: JSON.stringify(this.afterImages.filter(file => file.status === 'success').map(file => ({ | ||
| 434 | + name: file.name, | ||
| 435 | + url: file.url, | ||
| 436 | + fileId: file.fileId | ||
| 437 | + }))), | ||
| 438 | + remark: this.formData.remark, | ||
| 439 | + kjbRemark: this.formData.kjbRemark, | ||
| 440 | + // 语音备注(如果后端已支持会使用这些字段,未支持会忽略) | ||
| 441 | + voiceUrl: this.voiceNote.url || '', | ||
| 442 | + voiceDuration: this.voiceNote.duration || 0, | ||
| 443 | + voiceFileId: this.voiceNote.fileId || '' | ||
| 444 | + }; | ||
| 445 | + | ||
| 446 | + this.isSubmitting = true; | ||
| 447 | + uni.showLoading({ | ||
| 448 | + title: this.isEditMode ? '正在更新...' : '正在提交...' | ||
| 449 | + }); | ||
| 450 | + | ||
| 451 | + let result; | ||
| 452 | + if (this.isEditMode && this.logId) { | ||
| 453 | + // 编辑模式:调用更新接口 | ||
| 454 | + result = await lxApi.updateServiceLog({...submitData, id: this.logId}); | ||
| 455 | + } else { | ||
| 456 | + // 新增模式:调用创建接口 | ||
| 457 | + result = await lxApi.createServiceLog(submitData); | ||
| 458 | + } | ||
| 459 | + uni.hideLoading(); | ||
| 460 | + | ||
| 461 | + if (result.code === 200) { | ||
| 462 | + uni.showToast({ | ||
| 463 | + title: this.isEditMode ? '服务日志更新成功!' : '服务日志提交成功!', | ||
| 464 | + icon: 'success' | ||
| 465 | + }); | ||
| 466 | + | ||
| 467 | + // 返回上一页 | ||
| 468 | + setTimeout(() => { | ||
| 469 | + uni.navigateBack({ | ||
| 470 | + delta: 1 | ||
| 471 | + }); | ||
| 472 | + }, 1500); | ||
| 473 | + } else { | ||
| 474 | + uni.showToast({ | ||
| 475 | + title: result.msg || (this.isEditMode ? '更新失败!' : '提交失败!'), | ||
| 476 | + icon: 'none' | ||
| 477 | + }); | ||
| 478 | + } | ||
| 479 | + } catch (error) { | ||
| 480 | + uni.hideLoading(); | ||
| 481 | + console.error('提交失败:', error); | ||
| 482 | + uni.showToast({ | ||
| 483 | + title: '网络错误,请稍后重试', | ||
| 484 | + icon: 'none' | ||
| 485 | + }); | ||
| 486 | + } finally { | ||
| 487 | + this.isSubmitting = false; | ||
| 488 | + } | ||
| 489 | + }, | ||
| 490 | + | ||
| 491 | + // 初始化录音与播放 | ||
| 492 | + initRecorder() { | ||
| 493 | + if (this.recorderInited) return | ||
| 494 | + try { | ||
| 495 | + // 录音管理器 | ||
| 496 | + this.recorderManager = uni.getRecorderManager() | ||
| 497 | + this.recorderManager.onStart(() => { | ||
| 498 | + this.voiceNote.status = 'recording' | ||
| 499 | + }) | ||
| 500 | + this.recorderManager.onStop((res) => { | ||
| 501 | + this.voiceNote.status = 'processing' | ||
| 502 | + const tempFilePath = res.tempFilePath | ||
| 503 | + const duration = res.duration || 0 | ||
| 504 | + if (!tempFilePath) { | ||
| 505 | + this.voiceNote.status = 'idle' | ||
| 506 | + uni.showToast({ | ||
| 507 | + title: '未获取到录音文件', | ||
| 508 | + icon: 'none' | ||
| 509 | + }) | ||
| 510 | + return | ||
| 511 | + } | ||
| 512 | + this.handleVoiceFile(tempFilePath, duration) | ||
| 513 | + }) | ||
| 514 | + this.recorderManager.onError((err) => { | ||
| 515 | + console.error('录音失败:', err) | ||
| 516 | + this.voiceNote.status = 'idle' | ||
| 517 | + uni.showToast({ | ||
| 518 | + title: '录音失败,请检查权限', | ||
| 519 | + icon: 'none' | ||
| 520 | + }) | ||
| 521 | + }) | ||
| 522 | + | ||
| 523 | + // 播放器 | ||
| 524 | + this.audioContext = uni.createInnerAudioContext() | ||
| 525 | + this.audioContext.onPlay(() => { | ||
| 526 | + this.voiceNote.isPlaying = true | ||
| 527 | + }) | ||
| 528 | + this.audioContext.onPause(() => { | ||
| 529 | + this.voiceNote.isPlaying = false | ||
| 530 | + }) | ||
| 531 | + this.audioContext.onStop(() => { | ||
| 532 | + this.voiceNote.isPlaying = false | ||
| 533 | + }) | ||
| 534 | + this.audioContext.onEnded(() => { | ||
| 535 | + this.voiceNote.isPlaying = false | ||
| 536 | + }) | ||
| 537 | + | ||
| 538 | + this.recorderInited = true | ||
| 539 | + } catch (e) { | ||
| 540 | + console.error('初始化录音失败:', e) | ||
| 541 | + } | ||
| 542 | + }, | ||
| 543 | + | ||
| 544 | + // 开始/停止录音 | ||
| 545 | + toggleRecord() { | ||
| 546 | + if (!this.enableVoice) { | ||
| 547 | + uni.showToast({ | ||
| 548 | + title: '当前环境暂不支持录音', | ||
| 549 | + icon: 'none' | ||
| 550 | + }) | ||
| 551 | + return | ||
| 552 | + } | ||
| 553 | + if (!this.recorderInited) { | ||
| 554 | + this.initRecorder() | ||
| 555 | + } | ||
| 556 | + if (!this.recorderManager || typeof this.recorderManager.start !== 'function') { | ||
| 557 | + uni.showToast({ | ||
| 558 | + title: '当前环境暂不支持录音', | ||
| 559 | + icon: 'none' | ||
| 560 | + }) | ||
| 561 | + return | ||
| 562 | + } | ||
| 563 | + | ||
| 564 | + if (this.voiceNote.status === 'recording') { | ||
| 565 | + // 停止录音 | ||
| 566 | + this.recorderManager.stop() | ||
| 567 | + } else { | ||
| 568 | + // 开始录音 | ||
| 569 | + this.voiceNote.status = 'recording' | ||
| 570 | + this.voiceNote.duration = 0 | ||
| 571 | + this.voiceNote.uploading = false | ||
| 572 | + try { | ||
| 573 | + this.recorderManager.start({ | ||
| 574 | + duration: 600000, // 最长10分钟 | ||
| 575 | + format: 'mp3' | ||
| 576 | + }) | ||
| 577 | + } catch (e) { | ||
| 578 | + console.error('开始录音失败:', e) | ||
| 579 | + this.voiceNote.status = 'idle' | ||
| 580 | + uni.showToast({ | ||
| 581 | + title: '开始录音失败', | ||
| 582 | + icon: 'none' | ||
| 583 | + }) | ||
| 584 | + } | ||
| 585 | + } | ||
| 586 | + }, | ||
| 587 | + | ||
| 588 | + // 处理录音文件 | ||
| 589 | + async handleVoiceFile(tempFilePath, duration) { | ||
| 590 | + this.voiceNote.duration = Math.round(duration / 1000) // 毫秒转秒 | ||
| 591 | + this.voiceNote.uploading = true | ||
| 592 | + | ||
| 593 | + const file = { | ||
| 594 | + path: tempFilePath, | ||
| 595 | + tempFilePath, | ||
| 596 | + size: 0, | ||
| 597 | + name: `voice_${Date.now()}.mp3`, | ||
| 598 | + type: 'audio/mp3' | ||
| 599 | + } | ||
| 600 | + | ||
| 601 | + try { | ||
| 602 | + const result = await lxApi.uploadFile(file) | ||
| 603 | + if (result.code === 200 && result.data) { | ||
| 604 | + this.voiceNote.url = result.data.url | ||
| 605 | + this.voiceNote.fileId = result.data.name | ||
| 606 | + this.voiceNote.status = 'recorded' | ||
| 607 | + uni.showToast({ | ||
| 608 | + title: '语音上传成功', | ||
| 609 | + icon: 'success' | ||
| 610 | + }) | ||
| 611 | + } else { | ||
| 612 | + throw new Error(result.msg || '上传失败') | ||
| 613 | + } | ||
| 614 | + } catch (error) { | ||
| 615 | + console.error('语音上传失败:', error) | ||
| 616 | + this.voiceNote.status = 'idle' | ||
| 617 | + this.voiceNote.url = '' | ||
| 618 | + this.voiceNote.fileId = '' | ||
| 619 | + this.voiceNote.duration = 0 | ||
| 620 | + uni.showToast({ | ||
| 621 | + title: '语音上传失败', | ||
| 622 | + icon: 'none' | ||
| 623 | + }) | ||
| 624 | + } finally { | ||
| 625 | + this.voiceNote.uploading = false | ||
| 626 | + } | ||
| 627 | + }, | ||
| 628 | + | ||
| 629 | + // 播放/暂停语音 | ||
| 630 | + togglePlayVoice() { | ||
| 631 | + if (!this.voiceNote.url) { | ||
| 632 | + uni.showToast({ | ||
| 633 | + title: '暂无语音可播放', | ||
| 634 | + icon: 'none' | ||
| 635 | + }) | ||
| 636 | + return | ||
| 637 | + } | ||
| 638 | + if (!this.audioContext) { | ||
| 639 | + this.initRecorder() | ||
| 640 | + } | ||
| 641 | + if (!this.audioContext) return | ||
| 642 | + | ||
| 643 | + if (this.voiceNote.isPlaying) { | ||
| 644 | + this.audioContext.pause() | ||
| 645 | + } else { | ||
| 646 | + this.audioContext.stop() | ||
| 647 | + const src = this.voiceNote.url.indexOf('http') === 0 ? this.voiceNote.url : (this.baseUrl + this.voiceNote.url) | ||
| 648 | + this.audioContext.src = src | ||
| 649 | + this.audioContext.play() | ||
| 650 | + } | ||
| 651 | + }, | ||
| 652 | + | ||
| 653 | + // 删除语音 | ||
| 654 | + removeVoice() { | ||
| 655 | + if (this.audioContext) { | ||
| 656 | + this.audioContext.stop() | ||
| 657 | + } | ||
| 658 | + this.voiceNote = { | ||
| 659 | + fileId: '', | ||
| 660 | + url: '', | ||
| 661 | + duration: 0, | ||
| 662 | + status: 'idle', | ||
| 663 | + uploading: false, | ||
| 664 | + isPlaying: false | ||
| 665 | + } | ||
| 666 | + }, | ||
| 667 | + | ||
| 668 | + // 语音时长显示 | ||
| 669 | + formatVoiceDuration(sec) { | ||
| 670 | + const s = sec || 0 | ||
| 671 | + if (s < 60) { | ||
| 672 | + return s + '秒' | ||
| 673 | + } | ||
| 674 | + const m = Math.floor(s / 60) | ||
| 675 | + const left = s % 60 | ||
| 676 | + return m + '分' + (left ? left + '秒' : '') | ||
| 677 | + } | ||
| 678 | + } | ||
| 679 | + } | ||
| 680 | +</script> | ||
| 681 | + | ||
| 682 | +<style lang="scss" scoped> | ||
| 683 | + .container { | ||
| 684 | + // height: 100vh; | ||
| 685 | + background: linear-gradient(135deg, #e8f5e9 0%, #b2dfdb 100%); | ||
| 686 | + padding: 40rpx; | ||
| 687 | + box-sizing: border-box; | ||
| 688 | + } | ||
| 689 | + | ||
| 690 | + .member-card { | ||
| 691 | + background: #fff; | ||
| 692 | + border-radius: 32rpx; | ||
| 693 | + box-shadow: 0 8rpx 32rpx rgba(76, 175, 80, 0.1); | ||
| 694 | + padding: 40rpx; | ||
| 695 | + margin-bottom: 40rpx; | ||
| 696 | + } | ||
| 697 | + | ||
| 698 | + .member-info { | ||
| 699 | + display: flex; | ||
| 700 | + align-items: center; | ||
| 701 | + } | ||
| 702 | + | ||
| 703 | + .member-avatar { | ||
| 704 | + width: 80rpx; | ||
| 705 | + height: 80rpx; | ||
| 706 | + background: linear-gradient(135deg, #4caf50 0%, #66bb6a 100%); | ||
| 707 | + border-radius: 50%; | ||
| 708 | + display: flex; | ||
| 709 | + align-items: center; | ||
| 710 | + justify-content: center; | ||
| 711 | + font-size: 40rpx; | ||
| 712 | + margin-right: 24rpx; | ||
| 713 | + } | ||
| 714 | + | ||
| 715 | + .member-details { | ||
| 716 | + flex: 1; | ||
| 717 | + } | ||
| 718 | + | ||
| 719 | + .member-name { | ||
| 720 | + font-size: 32rpx; | ||
| 721 | + font-weight: 600; | ||
| 722 | + color: #2e7d32; | ||
| 723 | + margin-bottom: 8rpx; | ||
| 724 | + } | ||
| 725 | + | ||
| 726 | + .member-id { | ||
| 727 | + font-size: 24rpx; | ||
| 728 | + color: #6a9c6a; | ||
| 729 | + } | ||
| 730 | + | ||
| 731 | + .form-card { | ||
| 732 | + background: #fff; | ||
| 733 | + border-radius: 32rpx; | ||
| 734 | + box-shadow: 0 8rpx 32rpx rgba(76, 175, 80, 0.1); | ||
| 735 | + overflow: hidden; | ||
| 736 | + flex: 1; | ||
| 737 | + } | ||
| 738 | + | ||
| 739 | + .form-content { | ||
| 740 | + padding: 48rpx; | ||
| 741 | + } | ||
| 742 | + | ||
| 743 | + .form-group { | ||
| 744 | + margin-bottom: 40rpx; | ||
| 745 | + } | ||
| 746 | + | ||
| 747 | + .form-group:last-child { | ||
| 748 | + margin-bottom: 0; | ||
| 749 | + } | ||
| 750 | + | ||
| 751 | + .form-label { | ||
| 752 | + display: block; | ||
| 753 | + margin-bottom: 16rpx; | ||
| 754 | + font-weight: bold; | ||
| 755 | + color: #388e3c; | ||
| 756 | + letter-spacing: 2rpx; | ||
| 757 | + font-size: 28rpx; | ||
| 758 | + } | ||
| 759 | + | ||
| 760 | + .input-wrapper { | ||
| 761 | + position: relative; | ||
| 762 | + } | ||
| 763 | + | ||
| 764 | + .textarea-input { | ||
| 765 | + background: #f9fff9; | ||
| 766 | + border: 3rpx solid #c8e6c9; | ||
| 767 | + border-radius: 20rpx; | ||
| 768 | + padding: 24rpx; | ||
| 769 | + font-size: 28rpx; | ||
| 770 | + color: #2e7d32; | ||
| 771 | + min-height: 200rpx; | ||
| 772 | + box-sizing: border-box; | ||
| 773 | + width: 100%; | ||
| 774 | + } | ||
| 775 | + | ||
| 776 | + /* 文件上传样式 */ | ||
| 777 | + .file-upload-area { | ||
| 778 | + border: 4rpx dashed #c8e6c9; | ||
| 779 | + border-radius: 24rpx; | ||
| 780 | + padding: 48rpx; | ||
| 781 | + text-align: center; | ||
| 782 | + background: linear-gradient(135deg, #f9fff9 0%, #e8f5e9 100%); | ||
| 783 | + cursor: pointer; | ||
| 784 | + min-height: 240rpx; | ||
| 785 | + display: flex; | ||
| 786 | + flex-direction: column; | ||
| 787 | + justify-content: center; | ||
| 788 | + position: relative; | ||
| 789 | + overflow: hidden; | ||
| 790 | + } | ||
| 791 | + | ||
| 792 | + .file-upload-text { | ||
| 793 | + display: flex; | ||
| 794 | + flex-direction: column; | ||
| 795 | + align-items: center; | ||
| 796 | + gap: 24rpx; | ||
| 797 | + color: #6a9c6a; | ||
| 798 | + font-size: 19rpx; | ||
| 799 | + position: relative; | ||
| 800 | + z-index: 1; | ||
| 801 | + } | ||
| 802 | + | ||
| 803 | + .file-upload-icon { | ||
| 804 | + font-size: 50rpx; | ||
| 805 | + opacity: 0.8; | ||
| 806 | + } | ||
| 807 | + | ||
| 808 | + .file-list { | ||
| 809 | + margin-top: 32rpx; | ||
| 810 | + text-align: left; | ||
| 811 | + max-height: 400rpx; | ||
| 812 | + overflow-y: auto; | ||
| 813 | + } | ||
| 814 | + | ||
| 815 | + .file-item { | ||
| 816 | + display: flex; | ||
| 817 | + align-items: center; | ||
| 818 | + justify-content: space-between; | ||
| 819 | + padding: 20rpx 24rpx; | ||
| 820 | + background: #fff; | ||
| 821 | + border: 1rpx solid #e8f5e9; | ||
| 822 | + border-radius: 12rpx; | ||
| 823 | + margin-bottom: 12rpx; | ||
| 824 | + font-size: 26rpx; | ||
| 825 | + box-shadow: 0 2rpx 8rpx rgba(67, 233, 123, 0.08); | ||
| 826 | + transition: all 0.3s ease; | ||
| 827 | + } | ||
| 828 | + | ||
| 829 | + .file-info { | ||
| 830 | + display: flex; | ||
| 831 | + align-items: center; | ||
| 832 | + gap: 20rpx; | ||
| 833 | + overflow: hidden; | ||
| 834 | + width: 40%; | ||
| 835 | + } | ||
| 836 | + | ||
| 837 | + .file-icon { | ||
| 838 | + font-size: 32rpx; | ||
| 839 | + width: 56rpx; | ||
| 840 | + height: 56rpx; | ||
| 841 | + display: flex; | ||
| 842 | + align-items: center; | ||
| 843 | + justify-content: center; | ||
| 844 | + background: linear-gradient(135deg, #f9fff9 0%, #e8f5e9 100%); | ||
| 845 | + border-radius: 10rpx; | ||
| 846 | + flex-shrink: 0; | ||
| 847 | + border: 1rpx solid #c8e6c9; | ||
| 848 | + } | ||
| 849 | + | ||
| 850 | + .file-name { | ||
| 851 | + font-size: 28rpx; | ||
| 852 | + color: #333; | ||
| 853 | + font-weight: 500; | ||
| 854 | + overflow: hidden; | ||
| 855 | + text-overflow: ellipsis; | ||
| 856 | + white-space: nowrap; | ||
| 857 | + line-height: 1.4; | ||
| 858 | + } | ||
| 859 | + | ||
| 860 | + .file-actions { | ||
| 861 | + display: flex; | ||
| 862 | + align-items: center; | ||
| 863 | + gap: 12rpx; | ||
| 864 | + flex-shrink: 0; | ||
| 865 | + width: 55%; | ||
| 866 | + } | ||
| 867 | + | ||
| 868 | + .file-status { | ||
| 869 | + font-size: 22rpx; | ||
| 870 | + padding: 6rpx 12rpx; | ||
| 871 | + border-radius: 6rpx; | ||
| 872 | + font-weight: 500; | ||
| 873 | + white-space: nowrap; | ||
| 874 | + } | ||
| 875 | + | ||
| 876 | + .file-status.success { | ||
| 877 | + color: #2e7d32; | ||
| 878 | + background: #e8f5e9; | ||
| 879 | + border: 1rpx solid #c8e6c9; | ||
| 880 | + } | ||
| 881 | + | ||
| 882 | + .file-status.error { | ||
| 883 | + color: #c62828; | ||
| 884 | + background: #ffebee; | ||
| 885 | + border: 1rpx solid #ffcdd2; | ||
| 886 | + } | ||
| 887 | + | ||
| 888 | + .file-status.uploading { | ||
| 889 | + color: #ef6c00; | ||
| 890 | + background: #fff3e0; | ||
| 891 | + border: 1rpx solid #ffe0b2; | ||
| 892 | + } | ||
| 893 | + | ||
| 894 | + .btn-error { | ||
| 895 | + background: #f44336; | ||
| 896 | + color: #fff; | ||
| 897 | + border: none; | ||
| 898 | + border-radius: 6rpx; | ||
| 899 | + font-size: 20rpx; | ||
| 900 | + } | ||
| 901 | + | ||
| 902 | + .btn-group { | ||
| 903 | + display: flex; | ||
| 904 | + gap: 24rpx; | ||
| 905 | + margin-top: 48rpx; | ||
| 906 | + } | ||
| 907 | + | ||
| 908 | + .btn { | ||
| 909 | + flex: 1; | ||
| 910 | + padding: 10rpx 40rpx; | ||
| 911 | + border: none; | ||
| 912 | + border-radius: 20rpx; | ||
| 913 | + font-size: 28rpx; | ||
| 914 | + font-weight: bold; | ||
| 915 | + cursor: pointer; | ||
| 916 | + transition: all 0.2s ease; | ||
| 917 | + letter-spacing: 2rpx; | ||
| 918 | + } | ||
| 919 | + | ||
| 920 | + .btn-primary { | ||
| 921 | + background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); | ||
| 922 | + color: #fff; | ||
| 923 | + box-shadow: 0 4rpx 16rpx rgba(67, 233, 123, 0.3); | ||
| 924 | + } | ||
| 925 | + | ||
| 926 | + .btn-primary:hover { | ||
| 927 | + box-shadow: 0 8rpx 32rpx rgba(67, 233, 123, 0.4); | ||
| 928 | + transform: translateY(-2rpx); | ||
| 929 | + } | ||
| 930 | + | ||
| 931 | + /* 语音备注样式 */ | ||
| 932 | + .voice-card { | ||
| 933 | + background: radial-gradient(circle at 0 0, rgba(129, 199, 132, 0.12), transparent 60%), | ||
| 934 | + radial-gradient(circle at 100% 100%, rgba(129, 212, 250, 0.16), transparent 55%), | ||
| 935 | + #f9fff9; | ||
| 936 | + border-radius: 24rpx; | ||
| 937 | + border: 2rpx solid #c8e6c9; | ||
| 938 | + padding: 24rpx 28rpx; | ||
| 939 | + display: flex; | ||
| 940 | + flex-direction: column; | ||
| 941 | + gap: 24rpx; | ||
| 942 | + position: relative; | ||
| 943 | + overflow: hidden; | ||
| 944 | + } | ||
| 945 | + | ||
| 946 | + .voice-card::before { | ||
| 947 | + content: ''; | ||
| 948 | + position: absolute; | ||
| 949 | + left: -40%; | ||
| 950 | + top: 0; | ||
| 951 | + width: 80%; | ||
| 952 | + height: 100%; | ||
| 953 | + background: linear-gradient(120deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, .65), rgba(255, 255, 255, 0)); | ||
| 954 | + transform: skewX(-20deg); | ||
| 955 | + animation: voiceShine 4s infinite; | ||
| 956 | + pointer-events: none; | ||
| 957 | + } | ||
| 958 | + | ||
| 959 | + .voice-card--disabled { | ||
| 960 | + opacity: 0.8; | ||
| 961 | + } | ||
| 962 | + | ||
| 963 | + .voice-main { | ||
| 964 | + display: flex; | ||
| 965 | + align-items: center; | ||
| 966 | + gap: 24rpx; | ||
| 967 | + } | ||
| 968 | + | ||
| 969 | + .voice-record-btn { | ||
| 970 | + width: 96rpx; | ||
| 971 | + height: 96rpx; | ||
| 972 | + border-radius: 50%; | ||
| 973 | + background: radial-gradient(circle at 30% 30%, #ffffff 0%, #81c784 60%, #4caf50 100%); | ||
| 974 | + display: flex; | ||
| 975 | + align-items: center; | ||
| 976 | + justify-content: center; | ||
| 977 | + box-shadow: 0 8rpx 20rpx rgba(76, 175, 80, 0.4); | ||
| 978 | + transition: all 0.2s ease; | ||
| 979 | + position: relative; | ||
| 980 | + } | ||
| 981 | + | ||
| 982 | + .voice-record-btn::after { | ||
| 983 | + content: ''; | ||
| 984 | + position: absolute; | ||
| 985 | + inset: 0; | ||
| 986 | + border-radius: inherit; | ||
| 987 | + border: 2rpx solid rgba(255, 255, 255, 0.7); | ||
| 988 | + opacity: 0; | ||
| 989 | + } | ||
| 990 | + | ||
| 991 | + /* 默认轻微呼吸动画 */ | ||
| 992 | + .voice-record-btn { | ||
| 993 | + animation: voiceBreath 2.4s ease-in-out infinite; | ||
| 994 | + } | ||
| 995 | + | ||
| 996 | + .voice-record-btn.recording { | ||
| 997 | + background: radial-gradient(circle at 30% 30%, #ffffff 0%, #ff8a80 60%, #e53935 100%); | ||
| 998 | + box-shadow: 0 10rpx 26rpx rgba(229, 57, 53, 0.5); | ||
| 999 | + transform: scale(1.05); | ||
| 1000 | + animation: voicePulse 1.2s ease-out infinite; | ||
| 1001 | + } | ||
| 1002 | + | ||
| 1003 | + .voice-record-btn.recording::after { | ||
| 1004 | + animation: voiceHalo 1.2s ease-out infinite; | ||
| 1005 | + } | ||
| 1006 | + | ||
| 1007 | + .voice-record-icon { | ||
| 1008 | + font-size: 44rpx; | ||
| 1009 | + } | ||
| 1010 | + | ||
| 1011 | + .voice-info { | ||
| 1012 | + display: flex; | ||
| 1013 | + flex-direction: column; | ||
| 1014 | + gap: 8rpx; | ||
| 1015 | + } | ||
| 1016 | + | ||
| 1017 | + .voice-status-text { | ||
| 1018 | + font-size: 26rpx; | ||
| 1019 | + color: #388e3c; | ||
| 1020 | + font-weight: 500; | ||
| 1021 | + transition: color 0.2s ease; | ||
| 1022 | + } | ||
| 1023 | + | ||
| 1024 | + .voice-record-btn.recording + .voice-info .voice-status-text { | ||
| 1025 | + color: #e53935; | ||
| 1026 | + } | ||
| 1027 | + | ||
| 1028 | + .voice-duration { | ||
| 1029 | + font-size: 22rpx; | ||
| 1030 | + color: #6a9c6a; | ||
| 1031 | + } | ||
| 1032 | + | ||
| 1033 | + .voice-actions { | ||
| 1034 | + margin-top: 8rpx; | ||
| 1035 | + display: flex; | ||
| 1036 | + align-items: center; | ||
| 1037 | + gap: 20rpx; | ||
| 1038 | + } | ||
| 1039 | + | ||
| 1040 | + .voice-wave { | ||
| 1041 | + display: flex; | ||
| 1042 | + align-items: flex-end; | ||
| 1043 | + gap: 4rpx; | ||
| 1044 | + height: 32rpx; | ||
| 1045 | + } | ||
| 1046 | + | ||
| 1047 | + .wave-bar { | ||
| 1048 | + width: 4rpx; | ||
| 1049 | + height: 8rpx; | ||
| 1050 | + border-radius: 999rpx; | ||
| 1051 | + background: #a5d6a7; | ||
| 1052 | + transition: height 0.2s ease; | ||
| 1053 | + } | ||
| 1054 | + | ||
| 1055 | + .voice-wave.playing .wave-bar:nth-child(1) { | ||
| 1056 | + animation: voiceWave 0.6s infinite ease-in-out; | ||
| 1057 | + } | ||
| 1058 | + | ||
| 1059 | + .voice-wave.playing .wave-bar:nth-child(2) { | ||
| 1060 | + animation: voiceWave 0.6s 0.1s infinite ease-in-out; | ||
| 1061 | + } | ||
| 1062 | + | ||
| 1063 | + .voice-wave.playing .wave-bar:nth-child(3) { | ||
| 1064 | + animation: voiceWave 0.6s 0.2s infinite ease-in-out; | ||
| 1065 | + } | ||
| 1066 | + | ||
| 1067 | + .voice-wave.playing .wave-bar:nth-child(4) { | ||
| 1068 | + animation: voiceWave 0.6s 0.3s infinite ease-in-out; | ||
| 1069 | + } | ||
| 1070 | + | ||
| 1071 | + .voice-wave.playing .wave-bar:nth-child(5) { | ||
| 1072 | + animation: voiceWave 0.6s 0.4s infinite ease-in-out; | ||
| 1073 | + } | ||
| 1074 | + | ||
| 1075 | + @keyframes voiceWave { | ||
| 1076 | + 0%, 100% { | ||
| 1077 | + height: 8rpx; | ||
| 1078 | + background: #a5d6a7; | ||
| 1079 | + } | ||
| 1080 | + 50% { | ||
| 1081 | + height: 28rpx; | ||
| 1082 | + background: #43a047; | ||
| 1083 | + } | ||
| 1084 | + } | ||
| 1085 | + | ||
| 1086 | + @keyframes voiceBreath { | ||
| 1087 | + 0%, 100% { | ||
| 1088 | + transform: scale(1); | ||
| 1089 | + box-shadow: 0 8rpx 20rpx rgba(76, 175, 80, 0.4); | ||
| 1090 | + } | ||
| 1091 | + 50% { | ||
| 1092 | + transform: scale(1.03); | ||
| 1093 | + box-shadow: 0 10rpx 26rpx rgba(76, 175, 80, 0.55); | ||
| 1094 | + } | ||
| 1095 | + } | ||
| 1096 | + | ||
| 1097 | + @keyframes voicePulse { | ||
| 1098 | + 0% { | ||
| 1099 | + transform: scale(1.02); | ||
| 1100 | + box-shadow: 0 10rpx 26rpx rgba(229, 57, 53, 0.55); | ||
| 1101 | + } | ||
| 1102 | + 50% { | ||
| 1103 | + transform: scale(1.12); | ||
| 1104 | + box-shadow: 0 16rpx 40rpx rgba(229, 57, 53, 0.6); | ||
| 1105 | + } | ||
| 1106 | + 100% { | ||
| 1107 | + transform: scale(1.02); | ||
| 1108 | + box-shadow: 0 10rpx 26rpx rgba(229, 57, 53, 0.55); | ||
| 1109 | + } | ||
| 1110 | + } | ||
| 1111 | + | ||
| 1112 | + @keyframes voiceHalo { | ||
| 1113 | + 0% { | ||
| 1114 | + transform: scale(1); | ||
| 1115 | + opacity: 0.7; | ||
| 1116 | + } | ||
| 1117 | + 100% { | ||
| 1118 | + transform: scale(1.4); | ||
| 1119 | + opacity: 0; | ||
| 1120 | + } | ||
| 1121 | + } | ||
| 1122 | + | ||
| 1123 | + @keyframes voiceShine { | ||
| 1124 | + 0% { | ||
| 1125 | + transform: translateX(-120%) skewX(-20deg); | ||
| 1126 | + opacity: 0; | ||
| 1127 | + } | ||
| 1128 | + 20% { | ||
| 1129 | + opacity: 1; | ||
| 1130 | + } | ||
| 1131 | + 60% { | ||
| 1132 | + transform: translateX(140%) skewX(-20deg); | ||
| 1133 | + opacity: 0; | ||
| 1134 | + } | ||
| 1135 | + 100% { | ||
| 1136 | + transform: translateX(140%) skewX(-20deg); | ||
| 1137 | + opacity: 0; | ||
| 1138 | + } | ||
| 1139 | + } | ||
| 1140 | + | ||
| 1141 | + .btn-plain { | ||
| 1142 | + background: #ffffff; | ||
| 1143 | + color: #388e3c; | ||
| 1144 | + border: 2rpx solid #c8e6c9; | ||
| 1145 | + border-radius: 12rpx; | ||
| 1146 | + padding: 8rpx 20rpx; | ||
| 1147 | + font-size: 24rpx; | ||
| 1148 | + } | ||
| 1149 | +</style> |
绿纤uni-app/pages/expansion/expansion.vue
| @@ -54,8 +54,8 @@ | @@ -54,8 +54,8 @@ | ||
| 54 | </u-form-item> | 54 | </u-form-item> |
| 55 | 55 | ||
| 56 | <!-- 提交按钮 --> | 56 | <!-- 提交按钮 --> |
| 57 | - <u-button type="primary" :loading="loading" :disabled="loading" @click="loading?null:handleFormSubmit()" | ||
| 58 | - :customStyle="buttonStyle"> | 57 | + <u-button type="primary" :loading="loading" :disabled="loading" |
| 58 | + @click="loading?null:handleFormSubmit()" :customStyle="buttonStyle"> | ||
| 59 | {{ loading ? '提交中...' : '保存' }} | 59 | {{ loading ? '提交中...' : '保存' }} |
| 60 | </u-button> | 60 | </u-button> |
| 61 | </u-form> | 61 | </u-form> |
| @@ -129,15 +129,24 @@ | @@ -129,15 +129,24 @@ | ||
| 129 | message: '请输入顾客姓名', | 129 | message: '请输入顾客姓名', |
| 130 | trigger: 'blur' | 130 | trigger: 'blur' |
| 131 | }], | 131 | }], |
| 132 | - customerPhone: [{ | 132 | + customerPhone: [ |
| 133 | + { | ||
| 133 | required: true, | 134 | required: true, |
| 134 | message: '请输入电话号码', | 135 | message: '请输入电话号码', |
| 135 | - trigger: 'blur' | 136 | + trigger: ['blur', 'change'] |
| 136 | }, | 137 | }, |
| 137 | { | 138 | { |
| 138 | - pattern: /^1[3-9]\d{9}$/, | ||
| 139 | - message: '请输入正确的手机号码', | ||
| 140 | - trigger: 'blur' | 139 | + validator: (rule, value, callback) => { |
| 140 | + const phone = String(value || '').trim() | ||
| 141 | + if (!phone) { | ||
| 142 | + callback(new Error('请输入电话号码')) | ||
| 143 | + } else if (!/^1[3-9]\d{9}$/.test(phone)) { | ||
| 144 | + callback(new Error('请输入正确的手机号码')) | ||
| 145 | + } else { | ||
| 146 | + callback() | ||
| 147 | + } | ||
| 148 | + }, | ||
| 149 | + trigger: ['blur', 'change'] | ||
| 141 | } | 150 | } |
| 142 | ], | 151 | ], |
| 143 | paymentMethod: [{ | 152 | paymentMethod: [{ |
| @@ -327,16 +336,25 @@ | @@ -327,16 +336,25 @@ | ||
| 327 | 336 | ||
| 328 | // 处理表单提交 | 337 | // 处理表单提交 |
| 329 | async handleFormSubmit() { | 338 | async handleFormSubmit() { |
| 330 | - console.error('【【【【【【') | ||
| 331 | try { | 339 | try { |
| 332 | - // 使用 uview 表单验证 | 340 | + // 先走 uview 自带必填等校验 |
| 333 | await this.$refs.form.validate() | 341 | await this.$refs.form.validate() |
| 334 | 342 | ||
| 343 | + // 再做一层自定义业务校验(尤其是手机号) | ||
| 344 | + const errors = await this.validateForm() | ||
| 345 | + if (errors && errors.length > 0) { | ||
| 346 | + uni.showToast({ | ||
| 347 | + title: errors[0], | ||
| 348 | + icon: 'none', | ||
| 349 | + duration: 2000 | ||
| 350 | + }) | ||
| 351 | + return | ||
| 352 | + } | ||
| 353 | + | ||
| 335 | // 收集表单数据 | 354 | // 收集表单数据 |
| 336 | const formData = this.collectFormData() | 355 | const formData = this.collectFormData() |
| 337 | console.log('表单数据:', formData) | 356 | console.log('表单数据:', formData) |
| 338 | 357 | ||
| 339 | - // 提交数据 | ||
| 340 | await this.submitExpansion(formData) | 358 | await this.submitExpansion(formData) |
| 341 | } catch (error) { | 359 | } catch (error) { |
| 342 | console.log('表单验证失败:', error) | 360 | console.log('表单验证失败:', error) |
| @@ -355,7 +373,8 @@ | @@ -355,7 +373,8 @@ | ||
| 355 | // console.error(pushUrl) | 373 | // console.error(pushUrl) |
| 356 | // return | 374 | // return |
| 357 | const res = await this.API.submitExpansion(data) | 375 | const res = await this.API.submitExpansion(data) |
| 358 | - | 376 | + // console.error(res) |
| 377 | + // return | ||
| 359 | if (res.code === 200 && res.data && res.data.entity) { | 378 | if (res.code === 200 && res.data && res.data.entity) { |
| 360 | let tkinfo = res.data | 379 | let tkinfo = res.data |
| 361 | 380 | ||
| @@ -390,7 +409,7 @@ | @@ -390,7 +409,7 @@ | ||
| 390 | // 格式化时间 | 409 | // 格式化时间 |
| 391 | const formatTime = (timestamp) => { | 410 | const formatTime = (timestamp) => { |
| 392 | const date = new Date(timestamp) | 411 | const date = new Date(timestamp) |
| 393 | - return uni.$u.timeFormat(date,'yyyy/mm/dd hh:MM') | 412 | + return uni.$u.timeFormat(date, 'yyyy/mm/dd hh:MM') |
| 394 | } | 413 | } |
| 395 | 414 | ||
| 396 | const datanew = { | 415 | const datanew = { |
绿纤uni-app/unpackage/dist/build/mp-weixin/pages/expansion/expansion.js
| 1 | -(global["webpackJsonp"]=global["webpackJsonp"]||[]).push([["pages/expansion/expansion"],{"0ac1":function(e,t,n){"use strict";n.r(t);var r=n("20b8"),a=n("2242");for(var o in a)["default"].indexOf(o)<0&&function(e){n.d(t,e,(function(){return a[e]}))}(o);n("9854");var i=n("828b"),u=Object(i["a"])(a["default"],r["b"],r["c"],!1,null,"6122c20a",null,!1,r["a"],void 0);t["default"]=u.exports},"20b8":function(e,t,n){"use strict";n.d(t,"b",(function(){return a})),n.d(t,"c",(function(){return o})),n.d(t,"a",(function(){return r}));var r={uForm:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-form/u-form")]).then(n.bind(null,"63f8"))},uFormItem:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-form-item/u-form-item")]).then(n.bind(null,"eabc"))},uPicker:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-picker/u-picker")]).then(n.bind(null,"0e74"))},uIcon:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-icon/u-icon")]).then(n.bind(null,"3f69"))},uInput:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-input/u-input")]).then(n.bind(null,"5f80"))},uTextarea:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-textarea/u-textarea")]).then(n.bind(null,"269f"))},uButton:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-button/u-button")]).then(n.bind(null,"11af"))}},a=function(){var e=this,t=e.$createElement;e._self._c;e._isMounted||(e.e0=function(t){e.showEventPicker=!1},e.e1=function(t){e.showEventPicker=!1},e.e2=function(t){e.showEventPicker=!0},e.e3=function(t){e.showPaymentPicker=!1},e.e4=function(t){e.showPaymentPicker=!1},e.e5=function(t){e.showPaymentPicker=!0},e.e6=function(t){e.showWeChatPicker=!1},e.e7=function(t){e.showWeChatPicker=!1},e.e8=function(t){e.showWeChatPicker=!0},e.e9=function(t){!e.loading&&e.handleFormSubmit()})},o=[]},2242:function(e,t,n){"use strict";n.r(t);var r=n("2567"),a=n.n(r);for(var o in r)["default"].indexOf(o)<0&&function(e){n.d(t,e,(function(){return r[e]}))}(o);t["default"]=a.a},2567:function(e,t,n){"use strict";(function(e){var r=n("47a9");Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=r(n("7eb4")),o=r(n("ee10")),i=(n("8f59"),{data:function(){return{loading:!1,userInfo:null,currentEventId:null,eventList:[],formData:{eventId:"",customerName:"",customerPhone:"",paymentMethod:"微信",isAddWeChat:"否",remarks:""},showEventPicker:!1,showPaymentPicker:!1,showWeChatPicker:!1,selectedEventName:"",paymentOptions:[{text:"微信",value:"微信"},{text:"支付宝",value:"支付宝"},{text:"现金",value:"现金"},{text:"银行转账",value:"银行转账"}],weChatOptions:[{text:"是",value:"是"},{text:"否",value:"否"}],rules:{eventId:[{required:!0,message:"请选择拓客活动",trigger:"change"}],customerName:[{required:!0,message:"请输入顾客姓名",trigger:"blur"}],customerPhone:[{required:!0,message:"请输入电话号码",trigger:"blur"},{pattern:/^1[3-9]\d{9}$/,message:"请输入正确的手机号码",trigger:"blur"}],paymentMethod:[{required:!0,message:"请选择支付方式",trigger:"change"}],isAddWeChat:[{required:!0,message:"请选择是否加微信",trigger:"change"}]},inputStyle:{backgroundColor:"#f9fff9",border:"3rpx solid #c8e6c9",borderRadius:"20rpx",padding:"24rpx",fontSize:"28rpx",color:"#2e7d32"},textareaStyle:{backgroundColor:"#f9fff9",border:"3rpx solid #c8e6c9",borderRadius:"20rpx",padding:"32rpx",fontSize:"28rpx",color:"#2e7d32"},buttonStyle:{width:"100%",height:"80rpx",borderRadius:"24rpx",fontSize:"32rpx",fontWeight:"600",letterSpacing:"2rpx",background:"linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)",boxShadow:"0 8rpx 32rpx rgba(67, 233, 123, 0.3)",marginTop:"64rpx",borderColor:"rgba(67, 233, 123, 0.3)"}}},onLoad:function(){this.initializePage()},methods:{initializePage:function(){var t=this;return(0,o.default)(a.default.mark((function n(){return a.default.wrap((function(n){while(1)switch(n.prev=n.next){case 0:if(n.prev=0,t.userInfo=e.getStorageSync("userInfo"),t.userInfo&&0!==Object.keys(t.userInfo).length){n.next=5;break}return e.reLaunch({url:"/pages/login/login"}),n.abrupt("return");case 5:return console.log("用户信息:",t.userInfo),t.setDefaultDateTime(),n.next=9,t.getCurrentEvent();case 9:n.next=15;break;case 11:n.prev=11,n.t0=n["catch"](0),console.error("页面初始化失败:",n.t0),e.showToast({title:"页面初始化失败,请刷新重试",icon:"none",duration:3e3});case 15:case"end":return n.stop()}}),n,null,[[0,11]])})))()},setDefaultDateTime:function(){this.formData.paymentMethod="微信",this.formData.isAddWeChat="否"},getCurrentEvent:function(){var e=this;return(0,o.default)(a.default.mark((function t(){var n;return a.default.wrap((function(t){while(1)switch(t.prev=t.next){case 0:return t.prev=0,t.next=3,e.API.getCurrentEvent(e.userInfo.userId);case 3:n=t.sent,200===n.code&&n.data&&n.data.length>0?(e.eventList=n.data.map((function(e){return{text:e.EventName,value:e.EventId}})),n.data.length>0&&(e.currentEventId=n.data[0].EventId,e.formData.eventId=e.currentEventId,e.selectedEventName=n.data[0].EventName,console.log("当前活动ID:",e.currentEventId))):console.warn("未找到当前活动"),t.next=10;break;case 7:t.prev=7,t.t0=t["catch"](0),console.error("获取当前活动失败:",t.t0);case 10:case"end":return t.stop()}}),t,null,[[0,7]])})))()},validateForm:function(){var e=this;return(0,o.default)(a.default.mark((function t(){var n,r,o;return a.default.wrap((function(t){while(1)switch(t.prev=t.next){case 0:return n=[],e.formData.eventId||n.push("请选择拓客活动"),e.formData.customerName.trim()||n.push("请输入顾客姓名"),r=e.formData.customerPhone.trim(),r?(o=/^1[3-9]\d{9}$/,o.test(r)||n.push("请输入正确的手机号码")):n.push("请输入电话号码"),e.formData.paymentMethod||n.push("请选择支付方式"),e.formData.isAddWeChat||n.push("请选择是否加微信"),t.abrupt("return",n);case 8:case"end":return t.stop()}}),t)})))()},collectFormData:function(){return{expansionTime:null,customerName:this.formData.customerName.trim(),customerPhone:this.formData.customerPhone.trim(),buyNumber:1,paymentMethod:this.formData.paymentMethod,isAddWeChat:this.formData.isAddWeChat,remarks:this.formData.remarks.trim(),expansionUserId:this.userInfo.userId,eventId:this.formData.eventId}},onEventConfirm:function(e){var t=e.value;this.formData.eventId=t[0].value,this.selectedEventName=t[0].text,this.showEventPicker=!1},onPaymentConfirm:function(e){var t=e.value;this.formData.paymentMethod=t[0].value,this.showPaymentPicker=!1},onWeChatConfirm:function(e){var t=e.value;this.formData.isAddWeChat=t[0].value,this.showWeChatPicker=!1},handleFormSubmit:function(){var e=this;return(0,o.default)(a.default.mark((function t(){var n;return a.default.wrap((function(t){while(1)switch(t.prev=t.next){case 0:return console.error("【【【【【【"),t.prev=1,t.next=4,e.$refs.form.validate();case 4:return n=e.collectFormData(),console.log("表单数据:",n),t.next=8,e.submitExpansion(n);case 8:t.next=13;break;case 10:t.prev=10,t.t0=t["catch"](1),console.log("表单验证失败:",t.t0);case 13:case"end":return t.stop()}}),t,null,[[1,10]])})))()},submitExpansion:function(t){var n=this;return(0,o.default)(a.default.mark((function r(){var o,i,u,c,s;return a.default.wrap((function(r){while(1)switch(r.prev=r.next){case 0:return r.prev=0,e.showLoading({title:"正在提交..."}),n.loading=!0,r.next=5,n.API.getEvent(t.eventId);case 5:return o=r.sent,i=o.data&&o.data.pushUrl?o.data.pushUrl:"",r.next=9,n.API.submitExpansion(t);case 9:if(u=r.sent,200!==u.code||!u.data||!u.data.entity){r.next=16;break}return c=u.data,r.next=14,n.sendWeChatNotification(c,t,i);case 14:r.next=19;break;case 16:e.hideLoading(),e.showToast({title:"添加失败:".concat((null===(s=u.data)||void 0===s?void 0:s.Message)||"未知错误"),icon:"none",duration:3e3}),n.loading=!1;case 19:r.next=27;break;case 21:r.prev=21,r.t0=r["catch"](0),console.error("提交失败:",r.t0),e.hideLoading(),e.showToast({title:"网络错误,请稍后重试",icon:"none",duration:3e3}),n.loading=!1;case 27:case"end":return r.stop()}}),r,null,[[0,21]])})))()},sendWeChatNotification:function(t,n,r){var i=this;return(0,o.default)(a.default.mark((function o(){var u,c,s,d,l;return a.default.wrap((function(a){while(1)switch(a.prev=a.next){case 0:return a.prev=0,d=function(t){var n=new Date(t);return e.$u.timeFormat(n,"yyyy/mm/dd hh:MM")},l={webhookUrl:r||"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=581c22a6-cb67-42e5-8c76-b8e90052e188",content:"🎉 拓客记录\n⏩门店:".concat((null===(u=t.storeinfo)||void 0===u?void 0:u.Dm)||"未知","\n⏩拓客人员:").concat(i.userInfo.userName||"未知","\n⏩战队:").concat((null===(c=t.entity)||void 0===c?void 0:c.TeamName)||"未知","\n⏩顾客姓名:").concat(n.customerName,"\n⏩电话号码:").concat(n.customerPhone,"\n⏩购买张数:").concat(n.buyNumber,"\n⏩拓客时间:").concat(d(null===(s=t.entity)||void 0===s?void 0:s.ExpansionTime),"\n⏩支付方式:").concat(n.paymentMethod,"\n⏩是否加微信:").concat(n.isAddWeChat,"\n⏩备注:").concat(n.remarks||"")},a.next=5,i.API.sendWeChatNotification(l);case 5:e.hideLoading(),e.showToast({title:"拓客数据提交成功!",icon:"success",duration:2e3}),i.loading=!1,i.clearForm(),a.next=14;break;case 11:a.prev=11,a.t0=a["catch"](0),console.error("发送微信通知失败:",a.t0);case 14:case"end":return a.stop()}}),o,null,[[0,11]])})))()},clearForm:function(){var e=this;try{if(this.formData={eventId:this.currentEventId||"",customerName:"",customerPhone:"",paymentMethod:"微信",isAddWeChat:"否",remarks:""},this.currentEventId&&this.eventList.length>0){var t=this.eventList.find((function(t){return t.value===e.currentEventId}));this.selectedEventName=t?t.text:""}else this.selectedEventName="";this.$refs.form&&this.$refs.form.clearValidate(),console.log("表单已清空")}catch(n){console.error("清空表单失败:",n)}}}});t.default=i}).call(this,n("df3c")["default"])},"34c6":function(e,t,n){},9854:function(e,t,n){"use strict";var r=n("34c6"),a=n.n(r);a.a},e61b:function(e,t,n){"use strict";(function(e,t){var r=n("47a9");n("2fec");r(n("3240"));var a=r(n("0ac1"));e.__webpack_require_UNI_MP_PLUGIN__=n,t(a.default)}).call(this,n("3223")["default"],n("df3c")["createPage"])}},[["e61b","common/runtime","common/vendor"]]]); | ||
| 2 | \ No newline at end of file | 1 | \ No newline at end of file |
| 2 | +(global["webpackJsonp"]=global["webpackJsonp"]||[]).push([["pages/expansion/expansion"],{"0ac1":function(e,t,n){"use strict";n.r(t);var r=n("79c0"),a=n("2242");for(var o in a)["default"].indexOf(o)<0&&function(e){n.d(t,e,(function(){return a[e]}))}(o);n("a2de");var i=n("828b"),u=Object(i["a"])(a["default"],r["b"],r["c"],!1,null,"05d8df92",null,!1,r["a"],void 0);t["default"]=u.exports},2242:function(e,t,n){"use strict";n.r(t);var r=n("2567"),a=n.n(r);for(var o in r)["default"].indexOf(o)<0&&function(e){n.d(t,e,(function(){return r[e]}))}(o);t["default"]=a.a},2567:function(e,t,n){"use strict";(function(e){var r=n("47a9");Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=r(n("7eb4")),o=r(n("ee10")),i=(n("8f59"),{data:function(){return{loading:!1,userInfo:null,currentEventId:null,eventList:[],formData:{eventId:"",customerName:"",customerPhone:"",paymentMethod:"微信",isAddWeChat:"否",remarks:""},showEventPicker:!1,showPaymentPicker:!1,showWeChatPicker:!1,selectedEventName:"",paymentOptions:[{text:"微信",value:"微信"},{text:"支付宝",value:"支付宝"},{text:"现金",value:"现金"},{text:"银行转账",value:"银行转账"}],weChatOptions:[{text:"是",value:"是"},{text:"否",value:"否"}],rules:{eventId:[{required:!0,message:"请选择拓客活动",trigger:"change"}],customerName:[{required:!0,message:"请输入顾客姓名",trigger:"blur"}],customerPhone:[{required:!0,message:"请输入电话号码",trigger:["blur","change"]},{validator:function(e,t,n){var r=String(t||"").trim();r?/^1[3-9]\d{9}$/.test(r)?n():n(new Error("请输入正确的手机号码")):n(new Error("请输入电话号码"))},trigger:["blur","change"]}],paymentMethod:[{required:!0,message:"请选择支付方式",trigger:"change"}],isAddWeChat:[{required:!0,message:"请选择是否加微信",trigger:"change"}]},inputStyle:{backgroundColor:"#f9fff9",border:"3rpx solid #c8e6c9",borderRadius:"20rpx",padding:"24rpx",fontSize:"28rpx",color:"#2e7d32"},textareaStyle:{backgroundColor:"#f9fff9",border:"3rpx solid #c8e6c9",borderRadius:"20rpx",padding:"32rpx",fontSize:"28rpx",color:"#2e7d32"},buttonStyle:{width:"100%",height:"80rpx",borderRadius:"24rpx",fontSize:"32rpx",fontWeight:"600",letterSpacing:"2rpx",background:"linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)",boxShadow:"0 8rpx 32rpx rgba(67, 233, 123, 0.3)",marginTop:"64rpx",borderColor:"rgba(67, 233, 123, 0.3)"}}},onLoad:function(){this.initializePage()},methods:{initializePage:function(){var t=this;return(0,o.default)(a.default.mark((function n(){return a.default.wrap((function(n){while(1)switch(n.prev=n.next){case 0:if(n.prev=0,t.userInfo=e.getStorageSync("userInfo"),t.userInfo&&0!==Object.keys(t.userInfo).length){n.next=5;break}return e.reLaunch({url:"/pages/login/login"}),n.abrupt("return");case 5:return console.log("用户信息:",t.userInfo),t.setDefaultDateTime(),n.next=9,t.getCurrentEvent();case 9:n.next=15;break;case 11:n.prev=11,n.t0=n["catch"](0),console.error("页面初始化失败:",n.t0),e.showToast({title:"页面初始化失败,请刷新重试",icon:"none",duration:3e3});case 15:case"end":return n.stop()}}),n,null,[[0,11]])})))()},setDefaultDateTime:function(){this.formData.paymentMethod="微信",this.formData.isAddWeChat="否"},getCurrentEvent:function(){var e=this;return(0,o.default)(a.default.mark((function t(){var n;return a.default.wrap((function(t){while(1)switch(t.prev=t.next){case 0:return t.prev=0,t.next=3,e.API.getCurrentEvent(e.userInfo.userId);case 3:n=t.sent,200===n.code&&n.data&&n.data.length>0?(e.eventList=n.data.map((function(e){return{text:e.EventName,value:e.EventId}})),n.data.length>0&&(e.currentEventId=n.data[0].EventId,e.formData.eventId=e.currentEventId,e.selectedEventName=n.data[0].EventName,console.log("当前活动ID:",e.currentEventId))):console.warn("未找到当前活动"),t.next=10;break;case 7:t.prev=7,t.t0=t["catch"](0),console.error("获取当前活动失败:",t.t0);case 10:case"end":return t.stop()}}),t,null,[[0,7]])})))()},validateForm:function(){var e=this;return(0,o.default)(a.default.mark((function t(){var n,r,o;return a.default.wrap((function(t){while(1)switch(t.prev=t.next){case 0:return n=[],e.formData.eventId||n.push("请选择拓客活动"),e.formData.customerName.trim()||n.push("请输入顾客姓名"),r=e.formData.customerPhone.trim(),r?(o=/^1[3-9]\d{9}$/,o.test(r)||n.push("请输入正确的手机号码")):n.push("请输入电话号码"),e.formData.paymentMethod||n.push("请选择支付方式"),e.formData.isAddWeChat||n.push("请选择是否加微信"),t.abrupt("return",n);case 8:case"end":return t.stop()}}),t)})))()},collectFormData:function(){return{expansionTime:null,customerName:this.formData.customerName.trim(),customerPhone:this.formData.customerPhone.trim(),buyNumber:1,paymentMethod:this.formData.paymentMethod,isAddWeChat:this.formData.isAddWeChat,remarks:this.formData.remarks.trim(),expansionUserId:this.userInfo.userId,eventId:this.formData.eventId}},onEventConfirm:function(e){var t=e.value;this.formData.eventId=t[0].value,this.selectedEventName=t[0].text,this.showEventPicker=!1},onPaymentConfirm:function(e){var t=e.value;this.formData.paymentMethod=t[0].value,this.showPaymentPicker=!1},onWeChatConfirm:function(e){var t=e.value;this.formData.isAddWeChat=t[0].value,this.showWeChatPicker=!1},handleFormSubmit:function(){var t=this;return(0,o.default)(a.default.mark((function n(){var r,o;return a.default.wrap((function(n){while(1)switch(n.prev=n.next){case 0:return n.prev=0,n.next=3,t.$refs.form.validate();case 3:return n.next=5,t.validateForm();case 5:if(r=n.sent,!(r&&r.length>0)){n.next=9;break}return e.showToast({title:r[0],icon:"none",duration:2e3}),n.abrupt("return");case 9:return o=t.collectFormData(),console.log("表单数据:",o),n.next=13,t.submitExpansion(o);case 13:n.next=18;break;case 15:n.prev=15,n.t0=n["catch"](0),console.log("表单验证失败:",n.t0);case 18:case"end":return n.stop()}}),n,null,[[0,15]])})))()},submitExpansion:function(t){var n=this;return(0,o.default)(a.default.mark((function r(){var o,i,u,c,s;return a.default.wrap((function(r){while(1)switch(r.prev=r.next){case 0:return r.prev=0,e.showLoading({title:"正在提交..."}),n.loading=!0,r.next=5,n.API.getEvent(t.eventId);case 5:return o=r.sent,i=o.data&&o.data.pushUrl?o.data.pushUrl:"",r.next=9,n.API.submitExpansion(t);case 9:if(u=r.sent,200!==u.code||!u.data||!u.data.entity){r.next=16;break}return c=u.data,r.next=14,n.sendWeChatNotification(c,t,i);case 14:r.next=19;break;case 16:e.hideLoading(),e.showToast({title:"添加失败:".concat((null===(s=u.data)||void 0===s?void 0:s.Message)||"未知错误"),icon:"none",duration:3e3}),n.loading=!1;case 19:r.next=27;break;case 21:r.prev=21,r.t0=r["catch"](0),console.error("提交失败:",r.t0),e.hideLoading(),e.showToast({title:"网络错误,请稍后重试",icon:"none",duration:3e3}),n.loading=!1;case 27:case"end":return r.stop()}}),r,null,[[0,21]])})))()},sendWeChatNotification:function(t,n,r){var i=this;return(0,o.default)(a.default.mark((function o(){var u,c,s,d,l;return a.default.wrap((function(a){while(1)switch(a.prev=a.next){case 0:return a.prev=0,d=function(t){var n=new Date(t);return e.$u.timeFormat(n,"yyyy/mm/dd hh:MM")},l={webhookUrl:r||"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=581c22a6-cb67-42e5-8c76-b8e90052e188",content:"🎉 拓客记录\n⏩门店:".concat((null===(u=t.storeinfo)||void 0===u?void 0:u.Dm)||"未知","\n⏩拓客人员:").concat(i.userInfo.userName||"未知","\n⏩战队:").concat((null===(c=t.entity)||void 0===c?void 0:c.TeamName)||"未知","\n⏩顾客姓名:").concat(n.customerName,"\n⏩电话号码:").concat(n.customerPhone,"\n⏩购买张数:").concat(n.buyNumber,"\n⏩拓客时间:").concat(d(null===(s=t.entity)||void 0===s?void 0:s.ExpansionTime),"\n⏩支付方式:").concat(n.paymentMethod,"\n⏩是否加微信:").concat(n.isAddWeChat,"\n⏩备注:").concat(n.remarks||"")},a.next=5,i.API.sendWeChatNotification(l);case 5:e.hideLoading(),e.showToast({title:"拓客数据提交成功!",icon:"success",duration:2e3}),i.loading=!1,i.clearForm(),a.next=14;break;case 11:a.prev=11,a.t0=a["catch"](0),console.error("发送微信通知失败:",a.t0);case 14:case"end":return a.stop()}}),o,null,[[0,11]])})))()},clearForm:function(){var e=this;try{if(this.formData={eventId:this.currentEventId||"",customerName:"",customerPhone:"",paymentMethod:"微信",isAddWeChat:"否",remarks:""},this.currentEventId&&this.eventList.length>0){var t=this.eventList.find((function(t){return t.value===e.currentEventId}));this.selectedEventName=t?t.text:""}else this.selectedEventName="";this.$refs.form&&this.$refs.form.clearValidate(),console.log("表单已清空")}catch(n){console.error("清空表单失败:",n)}}}});t.default=i}).call(this,n("df3c")["default"])},7445:function(e,t,n){},"79c0":function(e,t,n){"use strict";n.d(t,"b",(function(){return a})),n.d(t,"c",(function(){return o})),n.d(t,"a",(function(){return r}));var r={uForm:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-form/u-form")]).then(n.bind(null,"63f8"))},uFormItem:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-form-item/u-form-item")]).then(n.bind(null,"eabc"))},uPicker:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-picker/u-picker")]).then(n.bind(null,"0e74"))},uIcon:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-icon/u-icon")]).then(n.bind(null,"3f69"))},uInput:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-input/u-input")]).then(n.bind(null,"5f80"))},uTextarea:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-textarea/u-textarea")]).then(n.bind(null,"269f"))},uButton:function(){return Promise.all([n.e("common/vendor"),n.e("uni_modules/uview-ui/components/u-button/u-button")]).then(n.bind(null,"11af"))}},a=function(){var e=this,t=e.$createElement;e._self._c;e._isMounted||(e.e0=function(t){e.showEventPicker=!1},e.e1=function(t){e.showEventPicker=!1},e.e2=function(t){e.showEventPicker=!0},e.e3=function(t){e.showPaymentPicker=!1},e.e4=function(t){e.showPaymentPicker=!1},e.e5=function(t){e.showPaymentPicker=!0},e.e6=function(t){e.showWeChatPicker=!1},e.e7=function(t){e.showWeChatPicker=!1},e.e8=function(t){e.showWeChatPicker=!0},e.e9=function(t){!e.loading&&e.handleFormSubmit()})},o=[]},a2de:function(e,t,n){"use strict";var r=n("7445"),a=n.n(r);a.a},e61b:function(e,t,n){"use strict";(function(e,t){var r=n("47a9");n("2fec");r(n("3240"));var a=r(n("0ac1"));e.__webpack_require_UNI_MP_PLUGIN__=n,t(a.default)}).call(this,n("3223")["default"],n("df3c")["createPage"])}},[["e61b","common/runtime","common/vendor"]]]); | ||
| 3 | \ No newline at end of file | 3 | \ No newline at end of file |
绿纤uni-app/unpackage/dist/build/mp-weixin/pages/expansion/expansion.wxml
| 1 | -<view class="container data-v-6122c20a"><view class="form-card data-v-6122c20a"><view class="form-content data-v-6122c20a"><u-form vue-id="9be4b680-1" model="{{formData}}" rules="{{rules}}" labelPosition="top" labelWidth="200" data-ref="form" data-event-opts="{{[['^submit',[['handleFormSubmit']]]]}}" bind:submit="__e" class="data-v-6122c20a vue-ref" bind:__l="__l" vue-slots="{{['default']}}"><u-form-item vue-id="{{('9be4b680-2')+','+('9be4b680-1')}}" label="拓客活动" prop="eventId" required="{{true}}" class="data-v-6122c20a" bind:__l="__l" vue-slots="{{['default']}}"><u-picker vue-id="{{('9be4b680-3')+','+('9be4b680-2')}}" show="{{showEventPicker}}" columns="{{[eventList]}}" data-event-opts="{{[['^confirm',[['onEventConfirm']]],['^cancel',[['e0']]],['^close',[['e1']]]]}}" bind:confirm="__e" bind:cancel="__e" bind:close="__e" class="data-v-6122c20a" bind:__l="__l"></u-picker><view data-event-opts="{{[['tap',[['e2',['$event']]]]]}}" class="picker-trigger data-v-6122c20a" bindtap="__e"><text class="picker-text data-v-6122c20a">{{selectedEventName||'请选择拓客活动'}}</text><u-icon vue-id="{{('9be4b680-4')+','+('9be4b680-2')}}" name="arrow-down" size="16" color="#6a9c6a" class="data-v-6122c20a" bind:__l="__l"></u-icon></view></u-form-item><u-form-item vue-id="{{('9be4b680-5')+','+('9be4b680-1')}}" label="顾客姓名" prop="customerName" required="{{true}}" class="data-v-6122c20a" bind:__l="__l" vue-slots="{{['default']}}"><u-input bind:input="__e" vue-id="{{('9be4b680-6')+','+('9be4b680-5')}}" placeholder="请输入顾客姓名" border="none" customStyle="{{inputStyle}}" value="{{formData.customerName}}" data-event-opts="{{[['^input',[['__set_model',['$0','customerName','$event',[]],['formData']]]]]}}" class="data-v-6122c20a" bind:__l="__l"></u-input></u-form-item><u-form-item vue-id="{{('9be4b680-7')+','+('9be4b680-1')}}" label="电话号码" prop="customerPhone" required="{{true}}" class="data-v-6122c20a" bind:__l="__l" vue-slots="{{['default']}}"><u-input bind:input="__e" vue-id="{{('9be4b680-8')+','+('9be4b680-7')}}" placeholder="请输入电话号码" type="number" border="none" customStyle="{{inputStyle}}" value="{{formData.customerPhone}}" data-event-opts="{{[['^input',[['__set_model',['$0','customerPhone','$event',[]],['formData']]]]]}}" class="data-v-6122c20a" bind:__l="__l"></u-input></u-form-item><u-form-item vue-id="{{('9be4b680-9')+','+('9be4b680-1')}}" label="支付方式" prop="paymentMethod" required="{{true}}" class="data-v-6122c20a" bind:__l="__l" vue-slots="{{['default']}}"><u-picker vue-id="{{('9be4b680-10')+','+('9be4b680-9')}}" show="{{showPaymentPicker}}" columns="{{[paymentOptions]}}" data-event-opts="{{[['^confirm',[['onPaymentConfirm']]],['^cancel',[['e3']]],['^close',[['e4']]]]}}" bind:confirm="__e" bind:cancel="__e" bind:close="__e" class="data-v-6122c20a" bind:__l="__l"></u-picker><view data-event-opts="{{[['tap',[['e5',['$event']]]]]}}" class="picker-trigger data-v-6122c20a" bindtap="__e"><text class="picker-text data-v-6122c20a">{{formData.paymentMethod||'请选择支付方式'}}</text><u-icon vue-id="{{('9be4b680-11')+','+('9be4b680-9')}}" name="arrow-down" size="16" color="#6a9c6a" class="data-v-6122c20a" bind:__l="__l"></u-icon></view></u-form-item><u-form-item vue-id="{{('9be4b680-12')+','+('9be4b680-1')}}" label="是否加微信" prop="isAddWeChat" required="{{true}}" class="data-v-6122c20a" bind:__l="__l" vue-slots="{{['default']}}"><u-picker vue-id="{{('9be4b680-13')+','+('9be4b680-12')}}" show="{{showWeChatPicker}}" columns="{{[weChatOptions]}}" data-event-opts="{{[['^confirm',[['onWeChatConfirm']]],['^cancel',[['e6']]],['^close',[['e7']]]]}}" bind:confirm="__e" bind:cancel="__e" bind:close="__e" class="data-v-6122c20a" bind:__l="__l"></u-picker><view data-event-opts="{{[['tap',[['e8',['$event']]]]]}}" class="picker-trigger data-v-6122c20a" bindtap="__e"><text class="picker-text data-v-6122c20a">{{formData.isAddWeChat||'请选择是否加微信'}}</text><u-icon vue-id="{{('9be4b680-14')+','+('9be4b680-12')}}" name="arrow-down" size="16" color="#6a9c6a" class="data-v-6122c20a" bind:__l="__l"></u-icon></view></u-form-item><u-form-item vue-id="{{('9be4b680-15')+','+('9be4b680-1')}}" label="备注" prop="remarks" class="data-v-6122c20a" bind:__l="__l" vue-slots="{{['default']}}"><u-textarea bind:input="__e" vue-id="{{('9be4b680-16')+','+('9be4b680-15')}}" placeholder="请输入备注信息" border="none" customStyle="{{textareaStyle}}" height="{{120}}" value="{{formData.remarks}}" data-event-opts="{{[['^input',[['__set_model',['$0','remarks','$event',[]],['formData']]]]]}}" class="data-v-6122c20a" bind:__l="__l"></u-textarea></u-form-item><u-button vue-id="{{('9be4b680-17')+','+('9be4b680-1')}}" type="primary" loading="{{loading}}" disabled="{{loading}}" customStyle="{{buttonStyle}}" data-event-opts="{{[['^click',[['e9']]]]}}" bind:click="__e" class="data-v-6122c20a" bind:__l="__l" vue-slots="{{['default']}}">{{''+(loading?'提交中...':'保存')+''}}</u-button></u-form></view></view></view> | ||
| 2 | \ No newline at end of file | 1 | \ No newline at end of file |
| 2 | +<view class="container data-v-05d8df92"><view class="form-card data-v-05d8df92"><view class="form-content data-v-05d8df92"><u-form vue-id="9be4b680-1" model="{{formData}}" rules="{{rules}}" labelPosition="top" labelWidth="200" data-ref="form" data-event-opts="{{[['^submit',[['handleFormSubmit']]]]}}" bind:submit="__e" class="data-v-05d8df92 vue-ref" bind:__l="__l" vue-slots="{{['default']}}"><u-form-item vue-id="{{('9be4b680-2')+','+('9be4b680-1')}}" label="拓客活动" prop="eventId" required="{{true}}" class="data-v-05d8df92" bind:__l="__l" vue-slots="{{['default']}}"><u-picker vue-id="{{('9be4b680-3')+','+('9be4b680-2')}}" show="{{showEventPicker}}" columns="{{[eventList]}}" data-event-opts="{{[['^confirm',[['onEventConfirm']]],['^cancel',[['e0']]],['^close',[['e1']]]]}}" bind:confirm="__e" bind:cancel="__e" bind:close="__e" class="data-v-05d8df92" bind:__l="__l"></u-picker><view data-event-opts="{{[['tap',[['e2',['$event']]]]]}}" class="picker-trigger data-v-05d8df92" bindtap="__e"><text class="picker-text data-v-05d8df92">{{selectedEventName||'请选择拓客活动'}}</text><u-icon vue-id="{{('9be4b680-4')+','+('9be4b680-2')}}" name="arrow-down" size="16" color="#6a9c6a" class="data-v-05d8df92" bind:__l="__l"></u-icon></view></u-form-item><u-form-item vue-id="{{('9be4b680-5')+','+('9be4b680-1')}}" label="顾客姓名" prop="customerName" required="{{true}}" class="data-v-05d8df92" bind:__l="__l" vue-slots="{{['default']}}"><u-input bind:input="__e" vue-id="{{('9be4b680-6')+','+('9be4b680-5')}}" placeholder="请输入顾客姓名" border="none" customStyle="{{inputStyle}}" value="{{formData.customerName}}" data-event-opts="{{[['^input',[['__set_model',['$0','customerName','$event',[]],['formData']]]]]}}" class="data-v-05d8df92" bind:__l="__l"></u-input></u-form-item><u-form-item vue-id="{{('9be4b680-7')+','+('9be4b680-1')}}" label="电话号码" prop="customerPhone" required="{{true}}" class="data-v-05d8df92" bind:__l="__l" vue-slots="{{['default']}}"><u-input bind:input="__e" vue-id="{{('9be4b680-8')+','+('9be4b680-7')}}" placeholder="请输入电话号码" type="number" border="none" customStyle="{{inputStyle}}" value="{{formData.customerPhone}}" data-event-opts="{{[['^input',[['__set_model',['$0','customerPhone','$event',[]],['formData']]]]]}}" class="data-v-05d8df92" bind:__l="__l"></u-input></u-form-item><u-form-item vue-id="{{('9be4b680-9')+','+('9be4b680-1')}}" label="支付方式" prop="paymentMethod" required="{{true}}" class="data-v-05d8df92" bind:__l="__l" vue-slots="{{['default']}}"><u-picker vue-id="{{('9be4b680-10')+','+('9be4b680-9')}}" show="{{showPaymentPicker}}" columns="{{[paymentOptions]}}" data-event-opts="{{[['^confirm',[['onPaymentConfirm']]],['^cancel',[['e3']]],['^close',[['e4']]]]}}" bind:confirm="__e" bind:cancel="__e" bind:close="__e" class="data-v-05d8df92" bind:__l="__l"></u-picker><view data-event-opts="{{[['tap',[['e5',['$event']]]]]}}" class="picker-trigger data-v-05d8df92" bindtap="__e"><text class="picker-text data-v-05d8df92">{{formData.paymentMethod||'请选择支付方式'}}</text><u-icon vue-id="{{('9be4b680-11')+','+('9be4b680-9')}}" name="arrow-down" size="16" color="#6a9c6a" class="data-v-05d8df92" bind:__l="__l"></u-icon></view></u-form-item><u-form-item vue-id="{{('9be4b680-12')+','+('9be4b680-1')}}" label="是否加微信" prop="isAddWeChat" required="{{true}}" class="data-v-05d8df92" bind:__l="__l" vue-slots="{{['default']}}"><u-picker vue-id="{{('9be4b680-13')+','+('9be4b680-12')}}" show="{{showWeChatPicker}}" columns="{{[weChatOptions]}}" data-event-opts="{{[['^confirm',[['onWeChatConfirm']]],['^cancel',[['e6']]],['^close',[['e7']]]]}}" bind:confirm="__e" bind:cancel="__e" bind:close="__e" class="data-v-05d8df92" bind:__l="__l"></u-picker><view data-event-opts="{{[['tap',[['e8',['$event']]]]]}}" class="picker-trigger data-v-05d8df92" bindtap="__e"><text class="picker-text data-v-05d8df92">{{formData.isAddWeChat||'请选择是否加微信'}}</text><u-icon vue-id="{{('9be4b680-14')+','+('9be4b680-12')}}" name="arrow-down" size="16" color="#6a9c6a" class="data-v-05d8df92" bind:__l="__l"></u-icon></view></u-form-item><u-form-item vue-id="{{('9be4b680-15')+','+('9be4b680-1')}}" label="备注" prop="remarks" class="data-v-05d8df92" bind:__l="__l" vue-slots="{{['default']}}"><u-textarea bind:input="__e" vue-id="{{('9be4b680-16')+','+('9be4b680-15')}}" placeholder="请输入备注信息" border="none" customStyle="{{textareaStyle}}" height="{{120}}" value="{{formData.remarks}}" data-event-opts="{{[['^input',[['__set_model',['$0','remarks','$event',[]],['formData']]]]]}}" class="data-v-05d8df92" bind:__l="__l"></u-textarea></u-form-item><u-button vue-id="{{('9be4b680-17')+','+('9be4b680-1')}}" type="primary" loading="{{loading}}" disabled="{{loading}}" customStyle="{{buttonStyle}}" data-event-opts="{{[['^click',[['e9']]]]}}" bind:click="__e" class="data-v-05d8df92" bind:__l="__l" vue-slots="{{['default']}}">{{''+(loading?'提交中...':'保存')+''}}</u-button></u-form></view></view></view> | ||
| 3 | \ No newline at end of file | 3 | \ No newline at end of file |
绿纤uni-app/unpackage/dist/build/mp-weixin/pages/expansion/expansion.wxss
| 1 | -.container.data-v-6122c20a{font-family:PingFang SC,Microsoft YaHei,Arial,sans-serif;margin:0;height:100vh;background:linear-gradient(135deg,#e8f5e9,#b2dfdb);padding:40rpx;width:100%;box-sizing:border-box;overflow-y:scroll}.page-title.data-v-6122c20a{text-align:center;color:#388e3c;margin-bottom:36rpx;letter-spacing:4rpx;font-size:36rpx;font-weight:700}.form-card.data-v-6122c20a{background:#fff;border-radius:40rpx;box-shadow:0 16rpx 64rpx 0 rgba(76,175,80,.15);border:2rpx solid #e8f5e9;overflow:hidden}.form-content.data-v-6122c20a{padding:64rpx;box-sizing:border-box}.form-group.data-v-6122c20a{margin-bottom:48rpx}.form-group.data-v-6122c20a:last-child{margin-bottom:0}label.data-v-6122c20a{display:block;margin-bottom:20rpx;font-weight:600;color:#2e7d32;letter-spacing:1rpx;font-size:28rpx}.input-wrapper.data-v-6122c20a{position:relative}.input-icon.data-v-6122c20a{position:absolute;left:24rpx;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);width:40rpx;height:40rpx;color:#6a9c6a}input.data-v-6122c20a, | ||
| 2 | -textarea.data-v-6122c20a, | ||
| 3 | -._select.data-v-6122c20a, | ||
| 4 | -.form-select.data-v-6122c20a{width:100%;padding:24rpx;border:3rpx solid #c8e6c9;border-radius:20rpx;font-size:28rpx;transition:all .2s ease;background:#f9fff9;color:#2e7d32;font-family:inherit;box-sizing:border-box}textarea.data-v-6122c20a{min-height:200rpx;resize:vertical;padding:32rpx;line-height:1.5}._select.data-v-6122c20a{cursor:pointer;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236a9c6a' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E");background-position:right 24rpx center;background-repeat:no-repeat;background-size:32rpx;padding-right:80rpx;appearance:none;-webkit-appearance:none;-moz-appearance:none}._select.data-v-6122c20a:focus{outline:none;border-color:#43a047;box-shadow:0 0 0 6rpx rgba(76,175,80,.1);background-color:#fff}input.data-v-6122c20a:focus, | ||
| 5 | -textarea.data-v-6122c20a:focus, | ||
| 6 | -._select.data-v-6122c20a:focus, | ||
| 7 | -.form-select.data-v-6122c20a:focus{outline:none;border-color:#43a047;box-shadow:0 0 0 6rpx rgba(76,175,80,.1);background:#fff}input.data-v-6122c20a:disabled{background:#f5f5f5;color:#666;cursor:not-allowed}.btn.data-v-6122c20a{width:100%;padding:32rpx 40rpx;border:none;border-radius:24rpx;font-size:32rpx;font-weight:600;cursor:pointer;transition:all .3s ease;letter-spacing:2rpx;background:linear-gradient(135deg,#43e97b,#38f9d7);color:#fff;box-shadow:0 8rpx 32rpx rgba(67,233,123,.3);margin-top:64rpx}.btn.data-v-6122c20a:hover{box-shadow:0 12rpx 48rpx rgba(67,233,123,.4);-webkit-transform:translateY(-4rpx);transform:translateY(-4rpx)}.btn.data-v-6122c20a:active{-webkit-transform:translateY(0);transform:translateY(0)}.picker-trigger.data-v-6122c20a{display:flex;align-items:center;justify-content:space-between;width:100%;padding:24rpx;background:#f9fff9;border:3rpx solid #c8e6c9;border-radius:20rpx;font-size:28rpx;color:#2e7d32;transition:all .2s ease;box-sizing:border-box}.picker-trigger.data-v-6122c20a:active{border-color:#43a047;box-shadow:0 0 0 6rpx rgba(76,175,80,.1);background:#fff}.picker-text.data-v-6122c20a{flex:1;color:#2e7d32} | ||
| 8 | \ No newline at end of file | 1 | \ No newline at end of file |
| 2 | +.container.data-v-05d8df92{font-family:PingFang SC,Microsoft YaHei,Arial,sans-serif;margin:0;height:100vh;background:linear-gradient(135deg,#e8f5e9,#b2dfdb);padding:40rpx;width:100%;box-sizing:border-box;overflow-y:scroll}.page-title.data-v-05d8df92{text-align:center;color:#388e3c;margin-bottom:36rpx;letter-spacing:4rpx;font-size:36rpx;font-weight:700}.form-card.data-v-05d8df92{background:#fff;border-radius:40rpx;box-shadow:0 16rpx 64rpx 0 rgba(76,175,80,.15);border:2rpx solid #e8f5e9;overflow:hidden}.form-content.data-v-05d8df92{padding:64rpx;box-sizing:border-box}.form-group.data-v-05d8df92{margin-bottom:48rpx}.form-group.data-v-05d8df92:last-child{margin-bottom:0}label.data-v-05d8df92{display:block;margin-bottom:20rpx;font-weight:600;color:#2e7d32;letter-spacing:1rpx;font-size:28rpx}.input-wrapper.data-v-05d8df92{position:relative}.input-icon.data-v-05d8df92{position:absolute;left:24rpx;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);width:40rpx;height:40rpx;color:#6a9c6a}input.data-v-05d8df92, | ||
| 3 | +textarea.data-v-05d8df92, | ||
| 4 | +._select.data-v-05d8df92, | ||
| 5 | +.form-select.data-v-05d8df92{width:100%;padding:24rpx;border:3rpx solid #c8e6c9;border-radius:20rpx;font-size:28rpx;transition:all .2s ease;background:#f9fff9;color:#2e7d32;font-family:inherit;box-sizing:border-box}textarea.data-v-05d8df92{min-height:200rpx;resize:vertical;padding:32rpx;line-height:1.5}._select.data-v-05d8df92{cursor:pointer;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236a9c6a' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E");background-position:right 24rpx center;background-repeat:no-repeat;background-size:32rpx;padding-right:80rpx;appearance:none;-webkit-appearance:none;-moz-appearance:none}._select.data-v-05d8df92:focus{outline:none;border-color:#43a047;box-shadow:0 0 0 6rpx rgba(76,175,80,.1);background-color:#fff}input.data-v-05d8df92:focus, | ||
| 6 | +textarea.data-v-05d8df92:focus, | ||
| 7 | +._select.data-v-05d8df92:focus, | ||
| 8 | +.form-select.data-v-05d8df92:focus{outline:none;border-color:#43a047;box-shadow:0 0 0 6rpx rgba(76,175,80,.1);background:#fff}input.data-v-05d8df92:disabled{background:#f5f5f5;color:#666;cursor:not-allowed}.btn.data-v-05d8df92{width:100%;padding:32rpx 40rpx;border:none;border-radius:24rpx;font-size:32rpx;font-weight:600;cursor:pointer;transition:all .3s ease;letter-spacing:2rpx;background:linear-gradient(135deg,#43e97b,#38f9d7);color:#fff;box-shadow:0 8rpx 32rpx rgba(67,233,123,.3);margin-top:64rpx}.btn.data-v-05d8df92:hover{box-shadow:0 12rpx 48rpx rgba(67,233,123,.4);-webkit-transform:translateY(-4rpx);transform:translateY(-4rpx)}.btn.data-v-05d8df92:active{-webkit-transform:translateY(0);transform:translateY(0)}.picker-trigger.data-v-05d8df92{display:flex;align-items:center;justify-content:space-between;width:100%;padding:24rpx;background:#f9fff9;border:3rpx solid #c8e6c9;border-radius:20rpx;font-size:28rpx;color:#2e7d32;transition:all .2s ease;box-sizing:border-box}.picker-trigger.data-v-05d8df92:active{border-color:#43a047;box-shadow:0 0 0 6rpx rgba(76,175,80,.1);background:#fff}.picker-text.data-v-05d8df92{flex:1;color:#2e7d32} | ||
| 9 | \ No newline at end of file | 9 | \ No newline at end of file |
绿纤uni-app/unpackage/dist/build/mp-weixin/project.private.config.json
| 1 | { | 1 | { |
| 2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", | 2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", |
| 3 | - "libVersion": "3.14.1" | 3 | + "libVersion": "3.14.3" |
| 4 | } | 4 | } |
| 5 | \ No newline at end of file | 5 | \ No newline at end of file |
绿纤uni-app/unpackage/dist/build/mp-weixin/uni_modules/uview-ui/components/u-gap/u-gap.json
绿纤uni-app/unpackage/dist/build/mp-weixin/uni_modules/uview-ui/components/u-toolbar/u-toolbar.json
绿纤uni-app/unpackage/dist/dev/mp-weixin/pages/expansion/expansion.js
| @@ -341,11 +341,19 @@ var _default = { | @@ -341,11 +341,19 @@ var _default = { | ||
| 341 | customerPhone: [{ | 341 | customerPhone: [{ |
| 342 | required: true, | 342 | required: true, |
| 343 | message: '请输入电话号码', | 343 | message: '请输入电话号码', |
| 344 | - trigger: 'blur' | 344 | + trigger: ['blur', 'change'] |
| 345 | }, { | 345 | }, { |
| 346 | - pattern: /^1[3-9]\d{9}$/, | ||
| 347 | - message: '请输入正确的手机号码', | ||
| 348 | - trigger: 'blur' | 346 | + validator: function validator(rule, value, callback) { |
| 347 | + var phone = String(value || '').trim(); | ||
| 348 | + if (!phone) { | ||
| 349 | + callback(new Error('请输入电话号码')); | ||
| 350 | + } else if (!/^1[3-9]\d{9}$/.test(phone)) { | ||
| 351 | + callback(new Error('请输入正确的手机号码')); | ||
| 352 | + } else { | ||
| 353 | + callback(); | ||
| 354 | + } | ||
| 355 | + }, | ||
| 356 | + trigger: ['blur', 'change'] | ||
| 349 | }], | 357 | }], |
| 350 | paymentMethod: [{ | 358 | paymentMethod: [{ |
| 351 | required: true, | 359 | required: true, |
| @@ -571,36 +579,48 @@ var _default = { | @@ -571,36 +579,48 @@ var _default = { | ||
| 571 | handleFormSubmit: function handleFormSubmit() { | 579 | handleFormSubmit: function handleFormSubmit() { |
| 572 | var _this4 = this; | 580 | var _this4 = this; |
| 573 | return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4() { | 581 | return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4() { |
| 574 | - var formData; | 582 | + var errors, formData; |
| 575 | return _regenerator.default.wrap(function _callee4$(_context4) { | 583 | return _regenerator.default.wrap(function _callee4$(_context4) { |
| 576 | while (1) { | 584 | while (1) { |
| 577 | switch (_context4.prev = _context4.next) { | 585 | switch (_context4.prev = _context4.next) { |
| 578 | case 0: | 586 | case 0: |
| 579 | - console.error('【【【【【【'); | ||
| 580 | - _context4.prev = 1; | ||
| 581 | - _context4.next = 4; | 587 | + _context4.prev = 0; |
| 588 | + _context4.next = 3; | ||
| 582 | return _this4.$refs.form.validate(); | 589 | return _this4.$refs.form.validate(); |
| 583 | - case 4: | 590 | + case 3: |
| 591 | + _context4.next = 5; | ||
| 592 | + return _this4.validateForm(); | ||
| 593 | + case 5: | ||
| 594 | + errors = _context4.sent; | ||
| 595 | + if (!(errors && errors.length > 0)) { | ||
| 596 | + _context4.next = 9; | ||
| 597 | + break; | ||
| 598 | + } | ||
| 599 | + uni.showToast({ | ||
| 600 | + title: errors[0], | ||
| 601 | + icon: 'none', | ||
| 602 | + duration: 2000 | ||
| 603 | + }); | ||
| 604 | + return _context4.abrupt("return"); | ||
| 605 | + case 9: | ||
| 584 | // 收集表单数据 | 606 | // 收集表单数据 |
| 585 | formData = _this4.collectFormData(); | 607 | formData = _this4.collectFormData(); |
| 586 | console.log('表单数据:', formData); | 608 | console.log('表单数据:', formData); |
| 587 | - | ||
| 588 | - // 提交数据 | ||
| 589 | - _context4.next = 8; | ||
| 590 | - return _this4.submitExpansion(formData); | ||
| 591 | - case 8: | ||
| 592 | _context4.next = 13; | 609 | _context4.next = 13; |
| 610 | + return _this4.submitExpansion(formData); | ||
| 611 | + case 13: | ||
| 612 | + _context4.next = 18; | ||
| 593 | break; | 613 | break; |
| 594 | - case 10: | ||
| 595 | - _context4.prev = 10; | ||
| 596 | - _context4.t0 = _context4["catch"](1); | 614 | + case 15: |
| 615 | + _context4.prev = 15; | ||
| 616 | + _context4.t0 = _context4["catch"](0); | ||
| 597 | console.log('表单验证失败:', _context4.t0); | 617 | console.log('表单验证失败:', _context4.t0); |
| 598 | - case 13: | 618 | + case 18: |
| 599 | case "end": | 619 | case "end": |
| 600 | return _context4.stop(); | 620 | return _context4.stop(); |
| 601 | } | 621 | } |
| 602 | } | 622 | } |
| 603 | - }, _callee4, null, [[1, 10]]); | 623 | + }, _callee4, null, [[0, 15]]); |
| 604 | }))(); | 624 | }))(); |
| 605 | }, | 625 | }, |
| 606 | // 提交扩展邀约数据 | 626 | // 提交扩展邀约数据 |
绿纤uni-app/unpackage/dist/dev/mp-weixin/project.private.config.json
| @@ -4,6 +4,20 @@ | @@ -4,6 +4,20 @@ | ||
| 4 | "miniprogram": { | 4 | "miniprogram": { |
| 5 | "list": [ | 5 | "list": [ |
| 6 | { | 6 | { |
| 7 | + "name": "pages/expansion/expansion", | ||
| 8 | + "pathName": "pages/expansion/expansion", | ||
| 9 | + "query": "", | ||
| 10 | + "launchMode": "default", | ||
| 11 | + "scene": null | ||
| 12 | + }, | ||
| 13 | + { | ||
| 14 | + "name": "pages/addServiceLog/addServiceLog", | ||
| 15 | + "pathName": "pages/addServiceLog/addServiceLog", | ||
| 16 | + "query": "consumeId=800705717190264069&memberName=%25E5%2588%2598%25E7%258E%2589%25E5%2585%25B0", | ||
| 17 | + "launchMode": "default", | ||
| 18 | + "scene": null | ||
| 19 | + }, | ||
| 20 | + { | ||
| 7 | "name": "pages/web/web", | 21 | "name": "pages/web/web", |
| 8 | "pathName": "pages/web/web", | 22 | "pathName": "pages/web/web", |
| 9 | "query": "url=https%253A%252F%252Ferp.lvqianmeiye.com%252Fhtml%252FdailyReport.html", | 23 | "query": "url=https%253A%252F%252Ferp.lvqianmeiye.com%252Fhtml%252FdailyReport.html", |