Explorar o código

feat(ui): 上传健康报告页面两种上传方式差异化重构

- 布局从横向并排改为上下分层 + 中间「或」分隔
- 方式 1(文件上传)虚线蓝框 + 蓝色基调 + 蓝色实心图标方块
- 方式 2(拍照上传)橙色边框 + 渐变橙色实心按钮(更醒目,即时操作)
- 顶部「方式 1/2」标签让用户明确二选一
- 保持 pickFile/takePhoto/selectedFile/photoPath/parsedInfo 逻辑不变
- 数据库初始化器同步上一轮的 report_summary 迁移(迁移 106)
Xiaogang Liao hai 3 meses
pai
achega
16c473f20a

+ 8 - 0
cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java

@@ -6129,6 +6129,14 @@ try {
 
 
     // 迁移136: payment_orders表添加period列(会员订阅周期)
     // 迁移136: payment_orders表添加period列(会员订阅周期)
     ensureColumn("payment_orders", "period", "VARCHAR(20) DEFAULT 'yearly' COMMENT '订阅周期: monthly/quarterly/yearly'");
     ensureColumn("payment_orders", "period", "VARCHAR(20) DEFAULT 'yearly' COMMENT '订阅周期: monthly/quarterly/yearly'");
+
+    // 迁移137: 扩大payment_orders.payment_type列长度(原列可能为VARCHAR(5),存不下"yearly")
+    try {
+        jdbcTemplate.execute("ALTER TABLE payment_orders MODIFY COLUMN payment_type VARCHAR(20) DEFAULT 'yearly' COMMENT '支付类型: yearly/monthly/trial'");
+        log.info("已修改payment_orders.payment_type列长度为VARCHAR(20)");
+    } catch (Exception e) {
+        log.warn("修改payment_orders.payment_type列长度失败: {}", e.getMessage());
+    }
     }
     }
 
 
     private void runMigration82() {
     private void runMigration82() {

+ 212 - 12
cfc-frontend/pages/health/report-upload.vue

@@ -61,19 +61,44 @@
 
 
     <!-- 表单 -->
     <!-- 表单 -->
     <view class="form-section">
     <view class="form-section">
-      <!-- 上传方式:两个入口 -->
-      <view class="form-item">
-        <text class="form-label">上传方式</text>
-        <view class="upload-type-row">
-          <view class="upload-type-card" @click="pickFile">
-            <text class="upload-type-icon">📄</text>
-            <text class="upload-type-name">上传文件</text>
-            <text class="upload-type-hint">PDF / 图片</text>
+      <!-- 上传方式:两种独立操作单元(上下分层,视觉差异明显) -->
+      <view class="upload-methods">
+        <!-- 方式 1:上传文件(PDF/Word/图片,从聊天记录选择) -->
+        <view class="upload-method method-file">
+          <view class="method-header">
+            <view class="method-tag tag-file">方式 1</view>
+            <text class="method-title">上传报告文件</text>
+            <text class="method-sub">体检报告、肠道检测报告等正式 PDF/Word 文档</text>
           </view>
           </view>
-          <view class="upload-type-card" @click="takePhoto">
-            <text class="upload-type-icon">📷</text>
-            <text class="upload-type-name">拍照上传</text>
-            <text class="upload-type-hint">舌象 / 报告照片</text>
+          <view class="method-body" @click="pickFile">
+            <view class="method-icon-file">📄</view>
+            <view class="method-cta-file">
+              <text class="method-cta-file-main">从微信聊天选择文件</text>
+              <text class="method-cta-file-sub">支持 PDF / Word / 图片</text>
+            </view>
+            <text class="method-arrow">›</text>
+          </view>
+        </view>
+
+        <!-- 分隔提示 -->
+        <view class="method-divider">
+          <text class="method-divider-text">或</text>
+        </view>
+
+        <!-- 方式 2:拍照上传(相机拍照,主要用于舌象) -->
+        <view class="upload-method method-photo">
+          <view class="method-header">
+            <view class="method-tag tag-photo">方式 2</view>
+            <text class="method-title">拍照上传</text>
+            <text class="method-sub">拍摄舌象照片或单页纸质报告</text>
+          </view>
+          <view class="method-body" @click="takePhoto">
+            <view class="method-icon-photo">📷</view>
+            <view class="method-cta-photo">
+              <text class="method-cta-photo-main">打开相机拍照</text>
+              <text class="method-cta-photo-sub">舌象分析 · 即拍即传</text>
+            </view>
+            <text class="method-arrow">›</text>
           </view>
           </view>
         </view>
         </view>
       </view>
       </view>
@@ -930,6 +955,181 @@ export default {
   height: 60rpx;
   height: 60rpx;
 }
 }
 
 
+/* ===== 上传方式(两种方式差异化) ===== */
+.upload-methods {
+  margin-bottom: 20rpx;
+}
+
+.upload-method {
+  background: #fff;
+  border-radius: 20rpx;
+  overflow: hidden;
+}
+
+/* 方式 1:文件上传(蓝色基调,大块虚线风格) */
+.method-file {
+  border: 2rpx dashed #93C5FD;
+  background: #F0F7FF;
+}
+.method-file .method-body {
+  background: #fff;
+  margin: 0 24rpx 24rpx;
+  border-radius: 16rpx;
+  padding: 32rpx 24rpx;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  border: 2rpx solid #DBEAFE;
+}
+.method-file .method-body:active {
+  background: #EFF6FF;
+}
+
+.method-tag {
+  display: inline-block;
+  font-size: 20rpx;
+  padding: 4rpx 14rpx;
+  border-radius: 20rpx;
+  margin-bottom: 12rpx;
+  font-weight: 500;
+}
+.tag-file {
+  background: #DBEAFE;
+  color: #1D4ED8;
+}
+.tag-photo {
+  background: #FED7AA;
+  color: #C2410C;
+}
+
+.method-header {
+  padding: 24rpx 24rpx 16rpx;
+}
+.method-title {
+  display: block;
+  font-size: 30rpx;
+  font-weight: bold;
+  color: #1E3A8A;
+  margin-bottom: 6rpx;
+}
+.method-sub {
+  display: block;
+  font-size: 22rpx;
+  color: #64748B;
+  line-height: 1.4;
+}
+
+.method-icon-file {
+  width: 88rpx;
+  height: 88rpx;
+  border-radius: 20rpx;
+  background: linear-gradient(135deg, #3B82F6, #1D4ED8);
+  color: #fff;
+  font-size: 48rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 20rpx;
+  flex-shrink: 0;
+  box-shadow: 0 4rpx 12rpx rgba(59, 130, 246, 0.3);
+}
+
+.method-cta-file {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+}
+.method-cta-file-main {
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #1E3A8A;
+  margin-bottom: 6rpx;
+}
+.method-cta-file-sub {
+  font-size: 22rpx;
+  color: #64748B;
+}
+
+.method-arrow {
+  font-size: 40rpx;
+  color: #94A3B8;
+  font-weight: 300;
+  margin-left: 12rpx;
+}
+
+/* 分隔提示 */
+.method-divider {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: center;
+  margin: 24rpx 0;
+}
+.method-divider-text {
+  font-size: 24rpx;
+  color: #94A3B8;
+  background: #F5F7FA;
+  padding: 6rpx 24rpx;
+  border-radius: 20rpx;
+  letter-spacing: 4rpx;
+}
+
+/* 方式 2:拍照上传(橙色基调,实心卡片风格) */
+.method-photo {
+  border: 2rpx solid #FED7AA;
+  background: #FFF7ED;
+}
+.method-photo .method-body {
+  background: linear-gradient(135deg, #FB923C, #EA580C);
+  margin: 0 24rpx 24rpx;
+  border-radius: 16rpx;
+  padding: 32rpx 24rpx;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  box-shadow: 0 6rpx 16rpx rgba(234, 88, 12, 0.25);
+}
+.method-photo .method-body:active {
+  opacity: 0.92;
+}
+
+.method-photo .method-title {
+  color: #7C2D12;
+}
+.method-icon-photo {
+  width: 88rpx;
+  height: 88rpx;
+  border-radius: 20rpx;
+  background: rgba(255, 255, 255, 0.95);
+  color: #EA580C;
+  font-size: 48rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 20rpx;
+  flex-shrink: 0;
+}
+
+.method-cta-photo {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+}
+.method-cta-photo-main {
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #fff;
+  margin-bottom: 6rpx;
+}
+.method-cta-photo-sub {
+  font-size: 22rpx;
+  color: rgba(255, 255, 255, 0.85);
+}
+
+.method-photo .method-arrow {
+  color: rgba(255, 255, 255, 0.9);
+}
+
 /* ===== 购买推荐 ===== */
 /* ===== 购买推荐 ===== */
 .purchase-section {
 .purchase-section {
   background: #F0F9FF;
   background: #F0F9FF;