Browse Source

订单对接微信接口

yuhongqi 1 day ago
parent
commit
897be094c2

+ 9 - 0
src/api/hisStore/storeOrder.js

@@ -377,3 +377,12 @@ export function getErpAccount() {
     method: 'get'
     method: 'get'
   })
   })
 }
 }
+
+// 导出发货单
+export function healthExportShippingOrder(query) {
+  return request({
+    url: '/store/store/storeOrder/healthExportShippingOrder',
+    method: 'get',
+    params: query
+  })
+}

+ 17 - 0
src/api/live/liveOrder.js

@@ -293,3 +293,20 @@ export function updateErp(data) {
     data: data
     data: data
   })
   })
 }
 }
+
+
+// 导出发货单
+export function healthExportShippingOrder(query) {
+  return request({
+    url: '/live/liveOrder/healthExportShippingOrder',
+    method: 'get',
+    params: query
+  })
+}
+
+export function importDeliveryNoteExpressTemplate() {
+  return request({
+    url: '/live/liveOrder/importDeliveryNoteExpressTemplate',
+    method: 'get'
+  })
+}

+ 67 - 21
src/views/hisStore/storeOrder/healthStoreList.vue

@@ -304,6 +304,16 @@
         >批量导入物流单号
         >批量导入物流单号
         </el-button>
         </el-button>
       </el-col>
       </el-col>
+      <el-col :span="1.5">
+        <el-button
+          v-hasPermi="['store:storeOrder:healthExportShippingOrder']"
+          icon="el-icon-tickets"
+          size="mini"
+          type="success"
+          @click="handleExportShippingOrder"
+        >导出发货单
+        </el-button>
+      </el-col>
       <el-col :span="1.5">
       <el-col :span="1.5">
         <el-button
         <el-button
           type="danger"
           type="danger"
@@ -724,24 +734,24 @@
       width="35%"
       width="35%"
     >
     >
       <span slot="footer" class="dialog-footer">
       <span slot="footer" class="dialog-footer">
-        <!-- 小程序Appid选择 -->
-<!--        <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">-->
-<!--          <el-form-item label="小程序:" prop="miniAppId">-->
-<!--        <el-select-->
-<!--          v-model="ruleForm.miniAppId"-->
-<!--          clearable-->
-<!--          placeholder="请选择发货小程序"-->
-<!--          style="width: 100%"-->
-<!--        >-->
-<!--          <el-option-->
-<!--            v-for="item in miniAppList"-->
-<!--            :key="item.appId"-->
-<!--            :label="item.appName"-->
-<!--            :value="item.appId"-->
-<!--          />-->
-<!--        </el-select>-->
-<!--      </el-form-item>-->
-<!--        </el-form>-->
+         小程序Appid选择
+        <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
+          <el-form-item label="小程序:" prop="miniAppId">
+        <el-select
+          v-model="ruleForm.miniAppId"
+          clearable
+          placeholder="请选择发货小程序"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="item in miniAppList"
+            :key="item.appId"
+            :label="item.appName"
+            :value="item.appId"
+          />
+        </el-select>
+      </el-form-item>
+        </el-form>
 
 
         <el-upload ref="upload" :action="orderUpload.url" :auto-upload="false" :disabled="orderUpload.isUploading" :headers="orderUpload.headers"
         <el-upload ref="upload" :action="orderUpload.url" :auto-upload="false" :disabled="orderUpload.isUploading" :headers="orderUpload.headers"
                    :limit="1" :on-progress="handleFileUploadProgress"
                    :limit="1" :on-progress="handleFileUploadProgress"
@@ -947,7 +957,7 @@ import {
   delStoreOrder,
   delStoreOrder,
   addStoreOrder,
   addStoreOrder,
   updateStoreOrder,
   updateStoreOrder,
-  exportHealthStoreOrder, exportHealthStoreOrderDetails, exportHealthStoreOrderItemsDetails,getErpAccount,
+  exportHealthStoreOrder, exportHealthStoreOrderDetails, exportHealthStoreOrderItemsDetails,getErpAccount,healthExportShippingOrder,
   queryErpPhone,
   queryErpPhone,
   saveErpPhone,editErpPhone,batchCreateErpOrder,batchSetErpOrder
   saveErpPhone,editErpPhone,batchCreateErpOrder,batchSetErpOrder
 } from '@/api/hisStore/storeOrder'
 } from '@/api/hisStore/storeOrder'
@@ -2360,7 +2370,7 @@ export default {
     //打开发货单
     //打开发货单
     openDeliveryNote() {
     openDeliveryNote() {
       this.deliveryNoteOpen = true
       this.deliveryNoteOpen = true
-      // this.getAppList();
+      this.getAppList();
     },
     },
     handleClose(done) {
     handleClose(done) {
       this.$confirm('确认关闭?')
       this.$confirm('确认关闭?')
@@ -2400,7 +2410,43 @@ export default {
         return;
         return;
       }
       }
       this.$refs.upload.submit();
       this.$refs.upload.submit();
-    }
+    },
+    handleExportShippingOrder() {
+      if (this.queryParams.status == '00') {
+        this.queryParams.status = null
+      }
+      if (this.createTimeRange != null && this.createTimeRange.length == 2) {
+        this.queryParams.createTimeRange = this.createTimeRange[0] + '--' + this.createTimeRange[1]
+      } else {
+        this.queryParams.createTimeRange = null
+      }
+      if (this.payTimeRange != null && this.payTimeRange.length == 2) {
+        this.queryParams.payTimeRange = this.payTimeRange[0] + '--' + this.payTimeRange[1]
+      } else {
+        this.queryParams.payTimeRange = null
+      }
+      if (this.deliveryImportTimeRange != null && this.deliveryImportTimeRange.length == 2) {
+        this.queryParams.deliveryImportTimeRange = this.deliveryImportTimeRange[0] + '--' + this.deliveryImportTimeRange[1]
+      } else {
+        this.queryParams.deliveryImportTimeRange = null
+      }
+      if (this.deliverySendTimeRange != null && this.deliverySendTimeRange.length == 2) {
+        this.queryParams.deliverySendTimeRange = this.deliverySendTimeRange[0] + '--' + this.deliverySendTimeRange[1]
+      } else {
+        this.queryParams.deliverySendTimeRange = null
+      }
+      const queryParams = this.addDateRange(this.queryParams, this.dateRange)
+      this.$confirm('是否确认导出所有订单明细数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return healthExportShippingOrder(queryParams)
+      }).then(response => {
+        this.download(response.msg)
+      }).catch(function() {
+      })
+    },
 
 
   }
   }
 }
 }

+ 629 - 730
src/views/live/liveData/index.vue

@@ -1,760 +1,659 @@
 <template>
 <template>
-  <div class="app-container">
-    <div class="title">近期直播</div>
-    <div class="live-container">
-      <div class="live-card" v-for="live in displayLives" :key="live.id">
-        <!-- 直播状态 -->
-        <div class="status">已结束</div>
-
-        <!-- 直播信息 -->
-        <div class="content">
-          <img :src="live.image" alt="直播封面" class="cover-image" />
-          <div class="info">
-            <h3 class="live-title">{{ live.title }}</h3>
-            <p class="time">开播时间: {{ live.time }}</p>
-          </div>
-        </div>
-
-        <!-- 直播数据 -->
-        <div class="stats">
-          <div class="stat-item">
-            <p class="label">直播间浏览量</p>
-            <p class="value">{{ live.views }}</p>
+  <div class="el-container-md">
+    <!-- 数据统计指标展示区域 -->
+    <el-card class="statistics-card" shadow="never">
+      <el-row :gutter="20">
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">累计观看人数</div>
+            <div class="statistics-value">{{ statisticsData.totalViewers || 0 }}</div>
           </div>
           </div>
-          <div class="stat-item">
-            <p class="label">直播间访客数</p>
-            <p class="value">{{ live.visitors }}</p>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">
+              累计完课人数
+              <el-popover placement="top" width="200" trigger="click">
+                <div>
+                  <el-input-number v-model="completeWatchTime" :min="0" :precision="0" placeholder="看课时长(分钟)" style="width: 100%;"></el-input-number>
+                  <el-button type="primary" size="mini" style="width: 100%; margin-top: 10px;" @click="updateCompleteWatchTime('total')">确定</el-button>
+                </div>
+                <el-button slot="reference" size="mini" type="text" icon="el-icon-setting" style="margin-left: 5px;">设置</el-button>
+              </el-popover>
+            </div>
+            <div class="statistics-value">{{ statisticsData.totalCompletedCourses || 0 }}</div>
           </div>
           </div>
-        </div>
-      </div>
-    </div>
-    <!-- 直播趋势统计 -->
-    <div class="trend-section">
-      <div class="trend-header">
-        <h3>直播趋势</h3>
-        <div class="filter-container">
-        <!-- 时间范围选择(下拉框) -->
-          <span class="filter-label">时间筛选:</span>
-          <el-select v-model="selectedTimeRange" placeholder="选择时间范围" @change="changeTimeRange" style="width: 180px">
-            <el-option label="自然天" value="day"></el-option>
-            <el-option label="自然周" value="week"></el-option>
-            <el-option label="自然月" value="month"></el-option>
-          </el-select>
-
-          <!-- 日期选择器 -->
-          <!-- 选择日期 -->
-          <el-date-picker
-            v-model="selectedDate"
-            :type="datePickerType"
-            :format="selectedTimeRange === 'week' ? weekRange : dateFormat"
-            :value-format="valueFormat"
-            placeholder="选择日期"
-            style="width: 280px"
-            @change="changeDate"
-          ></el-date-picker>
-        </div>
-      </div>
-
-      <div class="trend-cards">
-        <div
-          class="trend-card"
-          v-for="item in trendData"
-          :key="item.id"
-          :class="{ 'active': selectedMetric.id === item.id }"
-          @click="changeMetric(item)"
-        >
-          <div class="trend-header">
-            <p class="trend-title">{{ item.title }}</p>
-            <el-tooltip class="item" effect="dark" :content="item.tip" placement="top">
-              <i class="el-icon-info"></i>
-            </el-tooltip>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">直播观看人数</div>
+            <div class="statistics-value">{{ statisticsData.liveViewers || 0 }}</div>
           </div>
           </div>
-          <p class="trend-value">{{ item.value }}</p>
-          <p class="trend-change" :class="{ 'up': computedChange(item) > 0, 'down': computedChange(item) < 0 }">
-            {{ changeLabel }} {{ computedChange(item) }}%
-          </p>
-        </div>
-      </div>
-
-      <!-- 直播趋势折线图 -->
-      <div id="liveChart" class="chart"></div>
-    </div>
-    <div class="top10-section">
-      <h3>直播TOP10排行榜</h3>
-      <div class="ranking-container">
-          <!-- 红榜 -->
-          <div class="ranking-section red-rank">
-            <span class="rank-title">红榜</span>
-            <div class="rank-filters">
-              <button
-                v-for="item in redRankTypes"
-                :key="item.value"
-                :class="{ active: selectedRank === item.value }"
-                @click="selectRank(item.value)"
-              >
-                {{ item.label }}
-              </button>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">
+              直播完课人数
+              <el-popover placement="top" width="200" trigger="click">
+                <div>
+                  <el-input-number v-model="liveCompleteWatchTime" :min="0" :precision="0" placeholder="看课时长(分钟)" style="width: 100%;"></el-input-number>
+                  <el-button type="primary" size="mini" style="width: 100%; margin-top: 10px;" @click="updateCompleteWatchTime('live')">确定</el-button>
+                </div>
+                <el-button slot="reference" size="mini" type="text" icon="el-icon-setting" style="margin-left: 5px;">设置</el-button>
+              </el-popover>
             </div>
             </div>
+            <div class="statistics-value">{{ statisticsData.liveCompletedCourses || 0 }}</div>
           </div>
           </div>
-
-          <!-- 黑榜 -->
-          <div class="ranking-section black-rank">
-            <div class="rank-filters">
-              <button
-                v-for="item in blackRankTypes"
-                :key="item.value"
-                :class="{ active: selectedRank === item.value }"
-                @click="selectRank(item.value)"
-              >
-                {{ item.label }}
-              </button>
-            </div>
-            <span class="rank-title">黑榜</span>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">回放观看人数</div>
+            <div class="statistics-value">{{ statisticsData.playbackViewers || 0 }}</div>
           </div>
           </div>
-      </div>
-      <el-table :data="top10List" border style="width: 100%">
-        <el-table-column prop="rank" label="排名" width="80"></el-table-column>
-        <el-table-column prop="name" label="直播名称">
-          <template #default="scope">
-            <div class="live-name">
-              <img :src="scope.row.cover" class="live-cover" alt="封面">
-              <span class="live-title">{{ scope.row.name }}</span>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">
+              回放完课人数
+              <el-popover placement="top" width="200" trigger="click">
+                <div>
+                  <el-input-number v-model="replayCompleteWatchTime" :min="0" :precision="0" placeholder="看课时长(分钟)" style="width: 100%;"></el-input-number>
+                  <el-button type="primary" size="mini" style="width: 100%; margin-top: 10px;" @click="updateCompleteWatchTime('replay')">确定</el-button>
+                </div>
+                <el-button slot="reference" size="mini" type="text" icon="el-icon-setting" style="margin-left: 5px;">设置</el-button>
+              </el-popover>
             </div>
             </div>
-          </template>
-        </el-table-column>
-        <el-table-column prop="pv" label="直播间浏览量(PV)"></el-table-column>
-        <el-table-column prop="uv" label="直播间访客数(UV)"></el-table-column>
-        <el-table-column prop="watchPV" label="累计观看人次(PV)"></el-table-column>
-        <el-table-column prop="watchUV" label="累计观看人数(UV)"></el-table-column>
-        <el-table-column prop="avgTime" label="人均观看时长"></el-table-column>
-        <el-table-column prop="maxOnline" label="最高在线人数"></el-table-column>
-      </el-table>
+            <div class="statistics-value">{{ statisticsData.playbackCompletedCourses || 0 }}</div>
+          </div>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20" style="margin-top: 20px;">
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">直播峰值</div>
+            <div class="statistics-value">{{ statisticsData.livePeak || 0 }}</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">直播平均时长</div>
+            <div class="statistics-value">{{ formatDuration(statisticsData.liveAvgDuration) }}</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">回放平均时长</div>
+            <div class="statistics-value">{{ formatDuration(statisticsData.playbackAvgDuration) }}</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">GMV</div>
+            <div class="statistics-value">¥{{ statisticsData.gmv || 0 }}</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">付费人数</div>
+            <div class="statistics-value">{{ statisticsData.paidUsers || 0 }}</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">付费单数</div>
+            <div class="statistics-value">{{ statisticsData.paidOrders || 0 }}</div>
+          </div>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20" style="margin-top: 20px;">
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">销量统计</div>
+            <div class="statistics-value">{{ statisticsData.salesCount || 0 }}</div>
+          </div>
+        </el-col>
+      </el-row>
+    </el-card>
+
+    <!-- 筛选条件区域 -->
+    <el-form :model="queryParams" class="live-data-css" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="直播名称" prop="liveName">
+        <el-input
+          v-model="queryParams.liveName"
+          placeholder="请输入直播名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="观看类型" prop="watchType">
+        <el-select v-model="queryParams.watchType" placeholder="请选择观看类型" clearable size="small">
+          <el-option label="直播" value="live"></el-option>
+          <el-option label="回放" value="replay"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="完课状态" prop="completeStatus">
+        <el-select v-model="queryParams.completeStatus" placeholder="请选择完课状态" clearable size="small">
+          <el-option label="已完课" value="1"></el-option>
+          <el-option label="未完课" value="0"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="付费状态" prop="payStatus">
+        <el-select v-model="queryParams.payStatus" placeholder="请选择付费状态" clearable size="small">
+          <el-option label="已付费" value="1"></el-option>
+          <el-option label="未付费" value="0"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="观看时长" prop="watchDuration">
+        <el-input-number
+          v-model="queryParams.watchDuration"
+          :min="0"
+          :precision="0"
+          placeholder="观看时长(分钟)"
+          size="small"
+        ></el-input-number>
+      </el-form-item>
+      <el-form-item label="时间范围" prop="dateRange">
+        <el-date-picker
+          v-model="dateRange"
+          type="datetimerange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          size="small"
+          value-format="yyyy-MM-dd HH:mm:ss"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作工具栏 -->
+    <div class="selection-toolbar">
+      <el-checkbox :indeterminate="isIndeterminate" v-model="allChecked" @change="toggleSelectAll">
+        {{ multipleSelection.length > 0 ? `已选 ${multipleSelection.length} 条` : '选中本页' }}
+      </el-checkbox>
+      <!--      <el-button plain size="mini" @click="handleAutoTag">自动打标签</el-button>-->
+      <!--      <el-button plain size="mini" @click="handleAutoRemark">自动备注</el-button>-->
+      <el-button plain type="primary" size="mini" icon="el-icon-download" :loading="exportLoading" @click="handleExport">导出</el-button>
     </div>
     </div>
+
+    <!-- 数据表格 -->
+    <el-table
+      ref="dataTable"
+      :data="dataList"
+      style="width: 100%"
+      v-loading="loading"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55"></el-table-column>
+      <el-table-column type="index" label="序号" width="55" align="center"></el-table-column>
+      <el-table-column prop="liveName" label="直播间名称" min-width="160" show-overflow-tooltip></el-table-column>
+      <el-table-column prop="liveType" label="直播类型" width="100" align="center">
+        <template slot-scope="scope">
+          <el-tag type="danger" v-if="scope.row.liveType == 1">直播</el-tag>
+          <el-tag type="success" v-else-if="scope.row.liveType == 2">录播</el-tag>
+          <el-tag v-else-if="scope.row.liveType == 3">直播回放</el-tag>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="status" label="状态" width="100" align="center">
+        <template slot-scope="scope">
+          <el-tag type="info" v-if="scope.row.status == 1">未开始</el-tag>
+          <el-tag type="warning" v-else-if="scope.row.status == 2">进行中</el-tag>
+          <el-tag type="success" v-else-if="scope.row.status == 3">已结束</el-tag>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="startTime" label="开始时间" width="180" align="center"></el-table-column>
+      <el-table-column prop="finishTime" label="结束时间" width="180" align="center"></el-table-column>
+      <el-table-column prop="totalViewers" label="累计观看" width="110" align="center"></el-table-column>
+      <el-table-column prop="liveViewers" label="直播观看" width="110" align="center"></el-table-column>
+      <el-table-column prop="playbackViewers" label="回放观看" width="110" align="center"></el-table-column>
+      <el-table-column prop="liveAvgDuration" label="直播平均时长" width="140" align="center">
+        <template slot-scope="scope">{{ formatDuration(scope.row.liveAvgDuration) }}</template>
+      </el-table-column>
+      <el-table-column prop="playbackAvgDuration" label="回放平均时长" width="140" align="center">
+        <template slot-scope="scope">{{ formatDuration(scope.row.playbackAvgDuration) }}</template>
+      </el-table-column>
+      <el-table-column prop="totalCompletedCourses" label="累计完课" width="110" align="center"></el-table-column>
+      <el-table-column prop="liveCompletedCourses" label="直播完课" width="110" align="center"></el-table-column>
+      <el-table-column prop="playbackCompletedCourses" label="回放完课" width="110" align="center"></el-table-column>
+      <el-table-column prop="gmv" label="GMV" width="120" align="center">
+        <template slot-scope="scope">¥{{ scope.row.gmv || 0 }}</template>
+      </el-table-column>
+      <el-table-column prop="paidUsers" label="付费人数" width="100" align="center"></el-table-column>
+      <el-table-column prop="paidOrders" label="付费单数" width="100" align="center"></el-table-column>
+      <el-table-column prop="salesCount" label="销量统计" width="100" align="center"></el-table-column>
+      <el-table-column label="操作" width="120" fixed="right">
+        <template slot-scope="scope">
+          <el-button type="text" size="small" @click="handleViewDetail(scope.row)">查看详情</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页组件 -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+      style="margin-top: 20px;"
+    />
+
+    <!-- 自动打标签弹窗 -->
+    <el-dialog
+      title="自动打标签"
+      :visible.sync="tagDialogVisible"
+      width="600px"
+      :close-on-click-modal="false"
+    >
+      <el-form :model="tagForm" label-width="120px">
+        <el-form-item label="打标签规则">
+          <el-checkbox-group v-model="tagForm.rules">
+            <el-checkbox label="liveComplete">直播完课</el-checkbox>
+            <el-checkbox label="replayComplete">回放完课</el-checkbox>
+            <el-checkbox label="pay">付费行为</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item label="标签名称">
+          <el-input v-model="tagForm.tagName" placeholder="请输入标签名称"></el-input>
+        </el-form-item>
+        <el-form-item label="备注格式">
+          <el-radio-group v-model="tagForm.remarkFormat">
+            <el-radio label="time">时间—行为(如:2024-01-01—直播完课)</el-radio>
+            <el-radio label="simple">仅行为(如:直播完课)</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="tagDialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="confirmAutoTag">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 自动备注弹窗 -->
+    <el-dialog
+      title="自动备注"
+      :visible.sync="remarkDialogVisible"
+      width="600px"
+      :close-on-click-modal="false"
+    >
+      <el-form :model="remarkForm" label-width="120px">
+        <el-form-item label="备注规则">
+          <el-checkbox-group v-model="remarkForm.rules">
+            <el-checkbox label="liveComplete">直播完课</el-checkbox>
+            <el-checkbox label="replayComplete">回放完课</el-checkbox>
+            <el-checkbox label="pay">付费行为</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item label="备注格式">
+          <el-radio-group v-model="remarkForm.remarkFormat">
+            <el-radio label="time">时间—行为(如:2024-01-01—直播完课)</el-radio>
+            <el-radio label="simple">仅行为(如:直播完课)</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注位置">
+          <el-radio-group v-model="remarkForm.position">
+            <el-radio :label="1">添加在最前面</el-radio>
+            <el-radio :label="2">添加在最后面</el-radio>
+            <el-radio :label="3">替换所有备注</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="remarkDialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="confirmAutoRemark">确 定</el-button>
+      </div>
+    </el-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
-
 <script>
 <script>
-  import * as echarts from "echarts";
-  import { listLive, getLive, delLive, addLive, updateLive, exportLive } from "@/api/live/live";
-  import Editor from '@/components/Editor/wang';
-
-  export default {
-    name: "Live",
-    components: { Editor },
-    data() {
-      return {
-        top10List: [
-          {
-            rank: 1,
-            name: "御君方年末会员福利专场!",
-            cover:"https://cos.his.cdwjyyh.com/fs/20250304/710ea5b1896749b58438b76baf881d05.jpeg",
-            pv: 88332,
-            uv: 32674,
-            watchPV: 41866,
-            watchUV: 24714,
-            avgTime: "00:13:12",
-            maxOnline: 4317,
-          },
-          {
-            rank: 2,
-            name: "立秋养生大作战",
-            cover:"https://cos.his.cdwjyyh.com/fs/20250304/710ea5b1896749b58438b76baf881d05.jpeg",
-            pv: 55092,
-            uv: 15066,
-            watchPV: 33522,
-            watchUV: 12343,
-            avgTime: "01:18:30",
-            maxOnline: 3160,
-          },
-          {
-            rank: 3,
-            name: "寒露养生大挑战:防寒防燥防疾病",
-            cover:"https://cos.his.cdwjyyh.com/fs/20250304/710ea5b1896749b58438b76baf881d05.jpeg",
-            pv: 36044,
-            uv: 12205,
-            watchPV: 26056,
-            watchUV: 11086,
-            avgTime: "01:16:08",
-            maxOnline: 3232,
-          },
-        ],
-        selectedRank: 'highFlow',
-        redRankTypes: [
-          { label: '高流量', value: 'highFlow' },
-          { label: '高观看', value: 'highView' },
-          { label: '高时长', value: 'highTime' },
-        ],
-        blackRankTypes: [
-          { label: '低时长', value: 'lowTime' },
-          { label: '低观看', value: 'lowView' },
-          { label: '低流量', value: 'lowFlow' },
-        ],
-        selectedTimeRange: "day", // 默认选中“自然天”
-        datePickerType: "date", // 默认 date 类型
-        weekRange: "", // 存储选择周的时间范围
-        selectedDate: new Date().toISOString().split("T")[0], // 默认今天
-        lives: [
-          {
-            id: 1,
-            image: "https://cos.his.cdwjyyh.com/fs/20250117/d9e3b268e3834a2497e0bb1f900eac90.jpg",
-            title: "李悦的直播",
-            time: "2024-10-10 15:00:00",
-            views: 352821,
-            visitors: 14505,
-          },
-          {
-            id: 2,
-            image: "https://cos.his.cdwjyyh.com/fs/20250117/d9e3b268e3834a2497e0bb1f900eac90.jpg",
-            title: "小付的直播",
-            time: "2024-10-12 18:00:00",
-            views: 284210,
-            visitors: 10234,
-          },
-          {
-            id: 3,
-            image: "https://cos.his.cdwjyyh.com/fs/20250117/d9e3b268e3834a2497e0bb1f900eac90.jpg",
-            title: "生活妙招分享",
-            time: "2024-11-05 20:00:00",
-            views: 182401,
-            visitors: 8734,
-          },
-          {
-            id: 4,
-            image: "https://cos.his.cdwjyyh.com/fs/20250117/d9e3b268e3834a2497e0bb1f900eac90.jpg",
-            title: "家庭健康指南",
-            time: "2024-12-01 14:00:00",
-            views: 254321,
-            visitors: 12345,
-          },
-          {
-            id: 5,
-            image: "https://cos.his.cdwjyyh.com/fs/20250117/d9e3b268e3834a2497e0bb1f900eac90.jpg",
-            title: "额外的直播",
-            time: "2024-12-15 19:00:00",
-            views: 100000,
-            visitors: 5000,
-          }
-        ],
-        trendData: [
-          {
-            id: "views",
-            title: "直播间浏览量",
-            tip: "直播间总浏览量",
-            value: 352421,
-            dailyChange:1,
-            weeklyChange:2,
-            monthlyChange:3,
-            change: 5.2,
-            dates: ["02-02", "02-04", "02-06", "02-08", "02-10"],
-            data: [10, 20, 15, 25, 30],
-          },
-          {
-            id: "visitors",
-            title: "直播间访客数",
-            tip: "直播间访客数",
-            value: 14505,
-            dailyChange:1,
-            weeklyChange:2,
-            monthlyChange:3,
-            change: 5.2,
-            dates: ["02-02", "02-04", "02-06", "02-08", "02-10"],
-            data: [5, 8, 6, 10, 12],
-          },
-          {
-            id: "streams",
-            title: "创建直播数",
-            tip: "每日直播场次",
-            value: 20,
-            dailyChange:1,
-            weeklyChange:2,
-            monthlyChange:3,
-            change: 5.2,
-            dates: ["02-02", "02-04", "02-06", "02-08", "02-10"],
-            data: [1, 2, 1, 3, 2],
-          },
-          {
-            id: "pv",
-            title: "累计观看人次(PV)",
-            tip: "累计观看人次",
-            value: 5000,
-            dailyChange:1,
-            weeklyChange:2,
-            monthlyChange:3,
-            change: 5.2,
-            dates: ["02-02", "02-04", "02-06", "02-08", "02-10"],
-            data: [0, 0, 1, 0, 0],
-          },
-          {
-            id: "uv",
-            title: "累计观看人数(UV)",
-            tip: "累计观看人数",
-            value: 3000,
-            dailyChange:1,
-            weeklyChange:2,
-            monthlyChange:3,
-            change: 5.2,
-            dates: ["02-02", "02-04", "02-06", "02-08", "02-10"],
-            data: [0, 0, 0, 1, 0],
-          },
-        ],
-        selectedMetric: {}, // 选中的卡片数据
-        chart: null, // ECharts 实例
-      };
-    },
-    computed: {
-      changeLabel() {
-        switch (this.selectedTimeRange) {
-          case 'day': return '比前一天';
-          case 'week': return '比上周';
-          case 'month': return '比上月';
-          default: return '变化';
-        }
-      },
-      displayLives() {
-        return this.lives.slice(0, 4); // 最多只显示前 4 条数据
+import { listLiveData, exportLiveData, autoTagAndRemark, dashboardData } from "@/api/live/liveData";
+import { batchUpdateExternalContactNotes } from "@/api/qw/externalContact";
+import { addTag } from "@/api/qw/externalContact";
+
+export default {
+  name: "LiveData",
+  data() {
+    return {
+      liveId: '',
+      loading: true,
+      exportLoading: false,
+      showSearch: true,
+      dataList: [],
+      total: 0,
+      multipleSelection: [],
+      allChecked: false,
+      isIndeterminate: false,
+      dateRange: [],
+      // 统计数据
+      statisticsData: {
+        gmv: 0,
+        liveAvgDuration: 0,
+        liveCompletedCourses: 0,
+        livePeak: 0,
+        liveViewers: 0,
+        paidOrders: 0,
+        paidUsers: 0,
+        playbackAvgDuration: 0,
+        playbackCompletedCourses: 0,
+        playbackViewers: 0,
+        salesCount: 0,
+        totalCompletedCourses: 0,
+        totalViewers: 1
       },
       },
-      /*datePickerType() {
-        return this.selectedTimeRange === "day"
-          ? "date"
-          : this.selectedTimeRange === "week"
-            ? "week"
-            : "month";
-      },*/
-      dateFormat() {
-        return this.selectedTimeRange === "day"
-          ? "yyyy-MM-dd"
-          : this.selectedTimeRange === "week"
-            ? "yyyy-MM-dd 至 yyyy-MM-dd"
-            : "yyyy-MM";
+      // 完课时长设置
+      completeWatchTime: 0,
+      liveCompleteWatchTime: 0,
+      replayCompleteWatchTime: 0,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        liveId: null,
+        liveName: null,
+        watchType: null,
+        completeStatus: null,
+        payStatus: null,
+        watchDuration: null,
+        startTime: null,
+        endTime: null
       },
       },
-      valueFormat() {
-        return this.selectedTimeRange === "day"
-          ? "yyyy-MM-dd"
-          : this.selectedTimeRange === "week"
-            ? "yyyy-MM-dd"
-            : "yyyy-MM";
+      // 打标签弹窗
+      tagDialogVisible: false,
+      tagForm: {
+        rules: [],
+        tagName: '',
+        remarkFormat: 'time'
       },
       },
+      // 备注弹窗
+      remarkDialogVisible: false,
+      remarkForm: {
+        rules: [],
+        remarkFormat: 'time',
+        position: 1
+      }
+    };
+  },
+  created() {
+    this.liveId = this.$route.query.liveId;
+    this.queryParams.liveId = this.liveId;
+
+    this.getList();
+  },
+  methods: {
+    /** 获取统计数据 */
+    getStatistics() {
+      if (!this.liveId) return;
+      dashboardData(this.liveId).then(response => {
+        if (response.code === 200) {
+          this.statisticsData = response.data || {};
+        }
+      });
+    },
+    /** 获取列表数据 */
+    getList() {
+      this.loading = true;
+      // 处理时间范围
+      if (this.dateRange && this.dateRange.length === 2) {
+        this.queryParams.startTime = this.dateRange[0];
+        this.queryParams.endTime = this.dateRange[1];
+      } else {
+        this.queryParams.startTime = null;
+        this.queryParams.endTime = null;
+      }
+      listLiveData(this.queryParams).then(response => {
+        if (response.code === 200) {
+          this.statisticsData = response.data || {};
+          this.dataList = response.list || [];
+          this.total = response.total || 0;
+        }
+        this.loading = false;
+      }).catch(() => {
+        this.loading = false;
+      });
     },
     },
-    created() {
-      //this.getList();
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
     },
     },
-    mounted() {
-      this.selectedMetric = this.trendData[0]; // 默认选中第一个
-      this.initChart(); // 初始化折线图
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.$refs.queryForm.resetFields();
+      this.handleQuery();
     },
     },
-    methods: {
-      changeDate(value) {
-        if (this.selectedTimeRange === "week" && value) {
-          /*console.log("🟢 监听到 selectedWeek 变化:", newVal);*/
-          this.weekRange = this.getWeekRange(value);
-        } else {
-          this.weekRange = "";
-        }
-        console.log("选择的时间:", value, "筛选方式:", this.selectedTimeRange);
-      },
-      getWeekRange(selectedWeek) {
-        console.log("🔹 selectedWeek 输入值:", selectedWeek); // 检查传入值
-        let date = new Date(selectedWeek);
-
-        if (isNaN(date.getTime())) {
-          console.error("Invalid Date:", selectedWeek);
-          return "日期错误";
+    /** 全选或取消全选 */
+    toggleSelectAll(val) {
+      if (val) {
+        this.toggleSelection(this.dataList);
+      } else {
+        this.toggleSelection();
+      }
+    },
+    toggleSelection(rows) {
+      if (rows) {
+        rows.forEach(row => {
+          this.$refs.dataTable.toggleRowSelection(row);
+        });
+      } else {
+        this.$refs.dataTable.clearSelection();
+      }
+    },
+    /** 多选框选中数据 */
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+      this.allChecked = val.length === this.dataList.length;
+      this.isIndeterminate = val.length > 0 && val.length < this.dataList.length;
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      if (this.dateRange && this.dateRange.length === 2) {
+        this.queryParams.startTime = this.dateRange[0];
+        this.queryParams.endTime = this.dateRange[1];
+      } else {
+        this.queryParams.startTime = null;
+        this.queryParams.endTime = null;
+      }
+      this.$confirm('是否确认导出所有直播数据?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportLiveData(this.queryParams);
+      }).then(response => {
+        if (response.code === 200) {
+          this.download(response.msg);
         }
         }
-
-        let dayOfWeek = date.getDay(); // 0(星期天)- 6(星期六)
-
-        // 计算周一
-        let startDate = new Date(date); // 创建一个新的 Date 实例
-        startDate.setDate(date.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1));
-
-        // 计算周日(确保 `endDate` 是新实例)
-        let endDate = new Date(startDate.getTime()); // 复制 `startDate`
-        endDate.setDate(startDate.getDate() + 6);
-
-        console.log("周一:", this.formatDate(startDate));
-        console.log("周日:", this.formatDate(endDate));
-
-        return `${this.formatDate(startDate)} 至 ${this.formatDate(endDate)}`;
-      },
-      formatDate(date) {
-        const year = date.getFullYear();
-        const month = String(date.getMonth() + 1).padStart(2, "0");
-        const day = String(date.getDate()).padStart(2, "0");
-        return `${year}-${month}-${day}`;
-      },
-      computedChange(item) {
-        switch (this.selectedTimeRange) {
-          case 'day': return item.dailyChange;
-          case 'week': return item.weeklyChange;
-          case 'month': return item.monthlyChange;
-          default: return 0;
+        this.exportLoading = false;
+      }).catch(() => {
+        this.exportLoading = false;
+      });
+    },
+    /** 自动打标签 */
+    // handleAutoTag() {
+    //   if (this.multipleSelection.length === 0) {
+    //     this.$message.warning('请选择要打标签的数据');
+    //     return;
+    //   }
+    //   this.tagDialogVisible = true;
+    // },
+    /** 确认自动打标签 */
+    confirmAutoTag() {
+      if (this.tagForm.rules.length === 0) {
+        this.$message.warning('请选择打标签规则');
+        return;
+      }
+      const userIds = this.multipleSelection.map(item => item.userId).filter(id => id);
+      if (userIds.length === 0) {
+        this.$message.warning('所选数据中没有有效的用户ID');
+        return;
+      }
+      const data = {
+        userIds: userIds,
+        rules: this.tagForm.rules,
+        tagName: this.tagForm.tagName,
+        remarkFormat: this.tagForm.remarkFormat,
+        liveId: this.liveId
+      };
+      autoTagAndRemark(data).then(response => {
+        if (response.code === 200) {
+          this.$message.success('打标签成功');
+          this.tagDialogVisible = false;
+          this.tagForm = {
+            rules: [],
+            tagName: '',
+            remarkFormat: 'time'
+          };
+          this.getList();
         }
         }
-      },
-      selectRank(type) {
-        this.selectedRank = type; // 只允许一个按钮被选中
-        console.log(`选中的排行方式: ${type}`);
-      },
-      fetchRankingData() {
-        // 这里根据 `selectedRedRank` 和 `selectedBlackRank` 来请求不同的排行榜数据
-        console.log(`获取排行榜数据: 红榜-${this.selectedRedRank}, 黑榜-${this.selectedBlackRank}`);
-      },
-      // 切换时间范围
-      changeTimeRange() {
-        // 根据选中的时间范围修改 datePicker 类型
-        if (this.selectedTimeRange === "day") {
-          this.datePickerType = "date";
-        } else if (this.selectedTimeRange === "month") {
-          this.datePickerType = "month";
-        } else if (this.selectedTimeRange === "week") {
-          this.datePickerType = "week";
+      });
+    },
+    /** 自动备注 */
+    // handleAutoRemark() {
+    //   if (this.multipleSelection.length === 0) {
+    //     this.$message.warning('请选择要备注的数据');
+    //     return;
+    //   }
+    //   this.remarkDialogVisible = true;
+    // },
+    /** 确认自动备注 */
+    confirmAutoRemark() {
+      if (this.remarkForm.rules.length === 0) {
+        this.$message.warning('请选择备注规则');
+        return;
+      }
+      const userIds = this.multipleSelection.map(item => item.userId).filter(id => id);
+      if (userIds.length === 0) {
+        this.$message.warning('所选数据中没有有效的用户ID');
+        return;
+      }
+      // 生成备注内容
+      let notes = '';
+      const now = new Date();
+      const dateStr = now.getFullYear() + '-' +
+        String(now.getMonth() + 1).padStart(2, '0') + '-' +
+        String(now.getDate()).padStart(2, '0');
+
+      this.remarkForm.rules.forEach((rule, index) => {
+        let ruleText = '';
+        if (rule === 'liveComplete') {
+          ruleText = '直播完课';
+        } else if (rule === 'replayComplete') {
+          ruleText = '回放完课';
+        } else if (rule === 'pay') {
+          ruleText = '付费行为';
         }
         }
-        this.selectedDate = null; // 重置已选日期
-      },
-      // 切换时间(但目前只是选日期,没有请求后端)
-      /*changeDate() {
-        console.log("选择日期:", this.selectedDate);
-        // 这里可以做后端请求:this.fetchTrendData();
-      },*/
-      // 获取直播趋势数据
-      async fetchTrendData() {
-        try {
-          const response = await axios.get("/api/trend-data", { params: { date: this.selectedDate } });
-          this.trendData = response.data;
 
 
-          // 默认选择第一个指标
-          if (this.trendData.length > 0) {
-            this.changeMetric(this.trendData[0]);
-          }
-        } catch (error) {
-          console.error("获取直播数据失败:", error);
+        if (this.remarkForm.remarkFormat === 'time') {
+          notes += (index > 0 ? ';' : '') + dateStr + '—' + ruleText;
+        } else {
+          notes += (index > 0 ? ';' : '') + ruleText;
         }
         }
-      },
-      // 切换日期时更新数据
-      updateTrendData() {
-        console.log(`更新 ${this.selectedDate} 的直播数据`);
-        // 这里可以加接口请求,获取新的数据
-        this.updateChart();
-      },
-      // 切换指标
-      // changeMetric(metric) {
-      //   this.selectedMetric = metric;
-      //   this.updateChart();
-      // },
-      // updateTrendData() {
-      //   console.log("选择的时间:", this.selectedDate);
-      //   this.trendData = this.trendData.map(item => ({
-      //     ...item,
-      //     value: Math.floor(Math.random() * 50),
-      //     change: (Math.random() * 10 - 5).toFixed(2)
-      //   }));
-      //   this.updateChart();
-      // },
-      initChart() {
-        let chartDom = document.getElementById("liveChart");
-        if (!chartDom) return;
-        this.chart = echarts.init(chartDom);
-        this.updateChart();
-      },
-      // 更新折线图
-      updateChart() {
-        if (!this.chart) return;
-
-        let options = {
-          tooltip: { trigger: "axis", backgroundColor: "rgba(0, 0, 0, 0.7)", textStyle: { color: "#fff" } },
-          grid: { left: "5%", right: "5%", bottom: "10%", top: "10%", containLabel: true },
-          xAxis: { type: "category", data: this.selectedMetric.dates || [], axisLine: { lineStyle: { color: "#ddd" } } },
-          yAxis: { type: "value", splitLine: { lineStyle: { type: "dashed", color: "#ddd" } } },
-          series: [
-            {
-              name: this.selectedMetric.title,
-              data: this.selectedMetric.data || [],
-              type: "line",
-              smooth: true,
-              symbol: "circle",
-              symbolSize: 8,
-              itemStyle: { color: "#007BFF", borderColor: "#fff", borderWidth: 2 },
-              lineStyle: { width: 3, color: "#007BFF" },
-              areaStyle: {
-                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-                  { offset: 0, color: "rgba(0, 123, 255, 0.5)" },
-                  { offset: 1, color: "rgba(0, 123, 255, 0)" },
-                ]),
-              },
-              emphasis: {
-                focus: "series",
-                label: { show: true, formatter: "{c}", fontSize: 14, color: "#333", backgroundColor: "#fff", padding: [4, 6] },
-              },
-              animationDuration: 1200,
-              animationEasing: "quadraticOut",
-            },
-          ],
-        };
+      });
+
+      const data = {
+        userIds: userIds,
+        notes: notes,
+        type: this.remarkForm.position,
+        nameType: 3, // 不添加客户名称
+        filter: false
+      };
 
 
-        this.chart.setOption(options);
-      },
-      changeMetric(metric) {
-        this.selectedMetric = metric;
-        this.updateChart();
-      },
+      batchUpdateExternalContactNotes(data).then(response => {
+        if (response.code === 200) {
+          this.$message.success('备注成功');
+          this.remarkDialogVisible = false;
+          this.remarkForm = {
+            rules: [],
+            remarkFormat: 'time',
+            position: 1
+          };
+          this.getList();
+        }
+      });
+    },
+    /** 查看详情 */
+    handleViewDetail(row) {
+      // 可以跳转到详情页面或打开详情弹窗
+      this.$message.info('查看详情功能待实现');
+    },
+    /** 格式化时长 */
+    formatDuration(seconds) {
+      if (!seconds) return '00:00:00';
+      const hours = Math.floor(seconds / 3600);
+      const minutes = Math.floor((seconds % 3600) / 60);
+      const secs = seconds % 60;
+      return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
+    },
+    /** 更新完课时长设置 */
+    updateCompleteWatchTime(type) {
+      // 这里可以调用API保存设置
+      let watchTime = 0;
+      if (type === 'total') {
+        watchTime = this.completeWatchTime;
+      } else if (type === 'live') {
+        watchTime = this.liveCompleteWatchTime;
+      } else if (type === 'replay') {
+        watchTime = this.replayCompleteWatchTime;
+      }
+      // 更新查询参数并重新获取数据
+      this.queryParams.completeWatchTime = watchTime;
+      // this.getStatistics();
+      this.getList();
+      this.$message.success('设置成功');
     }
     }
-  };
+  }
+};
 </script>
 </script>
 
 
 <style scoped>
 <style scoped>
-  .app-container {
-    padding: 20px;
-  }
-
-  .title {
-    font-size: 18px;
-    font-weight: bold;
-    margin-bottom: 10px;
-  }
-  .live-container {
-    display: flex;
-    gap: 15px; /* 控制卡片之间的间距 */
-    overflow-x: auto; /* 允许横向滚动 */
-    padding-bottom: 10px;
-  }
-
-  /* 卡片样式 */
-  .live-card {
-    width: 380px;
-    height: 225px;
-    background: rgb(250,250,250);
-    border-radius: 10px;
-    padding: 15px;
-    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
-    display: flex;
-    flex-direction: column;
-    align-items: flex-start;
-  }
-
-  /* 直播状态 */
-  .status {
-    background: #d3d3d3;
-    color: #333;
-    font-size: 14px;
-    padding: 4px 8px;
-    border-radius: 5px;
-    display: inline-block;
-
-
-  }
-
-  /* 直播信息部分 */
-  .content {
-    background: rgb(250,250,250);
-    display: flex;
-    gap: 10px;
-    align-items: center;
-    width: 90%;
-    margin-top: 0px;
-  }
-
-  /* 直播封面图片 */
-  .cover-image {
-    width: 70px;
-    height: 70px;
-    border-radius: 10px;
-    object-fit: cover;
-  }
-
-  /* 直播文本信息 */
-  .info {
-    flex: 1;
-  }
-
-  .live-title {
-    font-size: 16px;
-    font-weight: bold;
-    white-space: nowrap;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    max-width: 250px; /* 防止标题过长 */
-  }
-
-  .time {
-    font-size: 14px;
-    color: #666;
-  }
-
-  /* 直播数据部分 */
-  .stats {
-    display: flex;
-    justify-content: space-between;
-    width: 100%;
-    flex-shrink: 0;
-    margin-top: -40px;
-  }
-
-  .stat-item {
-    text-align: center;
-    flex: 1;
-  }
-
-  .label {
-    font-size: 14px;
-    color: #888;
-  }
-
-  .value {
-    font-size: 18px;
-    font-weight: bold;
-    color: #333;
-  }
-  /* 直播趋势 */
-  .trend-section {
-    margin-top: 30px;
-  }
-  .trend-header {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-  }
-  .trend-cards {
-    display: flex;
-    gap: 15px;
-  }
-  .trend-card {
-    width: 280px;
-    hight: 100px;
-    border: 1px solid #ddd;
-    border-radius: 8px;
-    padding: 16px;
-    transition: all 0.3s;
-    position: relative;
-  }
-
-  .trend-card.active {
-    border-color: #007bff; /* 选中时边框变蓝 */
-    box-shadow: 0px 0px 10px rgba(0, 123, 255, 0.3);
-  }
-
-  .trend-card.active::after {
-    content: "✔";
-    position: absolute;
-    bottom: 8px;
-    right: 8px;
-    color: white;
-    background: #007bff;
-    border-radius: 50%;
-    width: 20px;
-    height: 20px;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    font-size: 14px;
-    font-weight: bold;
-  }
-  .trend-value {
-    font-size: 24px;
-    font-weight: bold;
-  }
-
-  /* 折线图 */
-  .chart {
-    width: 100%;
-    height: 300px;
-    margin-top: 20px;
-  }
-  .top10-section {
-    margin-top: 20px;
-    background: #fff;
-    padding: 16px;
-    border-radius: 8px;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-  }
-  .live-name {
-    display: flex;
-    align-items: center;
-  }
-
-  .live-cover {
-    width: 80px;  /* 直播封面宽度 */
-    height: 45px; /* 直播封面高度 */
-    border-radius: 4px;
-    margin-right: 10px;
-    object-fit: cover;
-  }
-
-  .live-title {
-    font-size: 14px;
-    color: #333;
-    white-space: nowrap;
-    overflow: hidden;
-    text-overflow: ellipsis;
-  }
-  .ranking-tabs {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    padding: 10px 20px;
-  }
-
-  .ranking-container {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    margin: 10px 0;
-    border-radius: 8px;
-    overflow: hidden;
-  }
-
-  .ranking-section {
-    display: flex;
-    align-items: center;
-    width: 50%;
-    padding: 10px 15px;
-  }
-
-  .red-rank {
-    background: linear-gradient(90deg, #ff6b6b, #ff8e8e);
-    justify-content: flex-start;
-  }
-
-  .black-rank {
-    background: linear-gradient(90deg, #4a4a4a, #6b6b6b);
-    justify-content: flex-end;
-  }
-
-  .rank-title {
-    font-size: 18px;
-    font-weight: bold;
-    color: white;
-    margin: 0 15px;
-  }
-
-  .rank-filters {
-    display: flex;
-  }
-
-  button {
-    background: rgba(255, 255, 255, 0.2);
-    border: 1px solid rgba(255, 255, 255, 0.5);
-    color: white;
-    font-size: 14px;
-    padding: 5px 12px;
-    margin: 0 5px;
-    border-radius: 15px;
-    cursor: pointer;
-    transition: all 0.3s ease;
-  }
-
-  button.active {
-    background: white;
-    color: #ff4d4f;
-  }
-  .filter-container {
-    display: flex;
-    align-items: center;
-    gap: 8px; /* 控制两个组件的间距 */
-  }
-
-  .filter-label {
-    font-weight: bold;
-    white-space: nowrap; /* 防止换行 */
-  }
+.statistics-card {
+  margin-bottom: 20px;
+}
+
+.statistics-item {
+  text-align: center;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+}
+
+.statistics-title {
+  font-size: 14px;
+  color: #606266;
+  margin-bottom: 10px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.statistics-value {
+  font-size: 24px;
+  font-weight: bold;
+  color: #303133;
+}
+
+.selection-toolbar {
+  display: flex;
+  align-items: center;
+  margin-bottom: 10px;
+  padding-left: 10px;
+}
+
+.selection-toolbar .el-checkbox {
+  margin-right: 10px;
+}
+
+.live-data-css {
+  padding-left: 10px;
+  padding-top: 30px;
+}
 </style>
 </style>
-

+ 209 - 3
src/views/live/liveOrder/index.vue

@@ -126,7 +126,26 @@
           :loading="exportLoading"
           :loading="exportLoading"
           @click="handleExport"
           @click="handleExport"
           v-hasPermi="['live:liveOrder:export']"
           v-hasPermi="['live:liveOrder:export']"
-        >导出</el-button>
+        >导出订单</el-button>
+        <el-col :span="1.5">
+          <el-button
+            icon="el-icon-s-order"
+            size="mini"
+            type="warning"
+            @click="openDeliveryNote"
+          >批量导入物流单号
+          </el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            v-hasPermi="['store:storeOrder:healthExportShippingOrder']"
+            icon="el-icon-tickets"
+            size="mini"
+            type="success"
+            @click="handleExportShippingOrder"
+          >导出发货单
+          </el-button>
+        </el-col>
       </el-col>
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
     </el-row>
@@ -217,16 +236,64 @@
       :title="show.title" :visible.sync="show.open">
       :title="show.title" :visible.sync="show.open">
       <liveOrderDetails ref="Details" />
       <liveOrderDetails ref="Details" />
     </el-drawer>
     </el-drawer>
+
+    <el-dialog
+      :before-close="handleClose"
+      :visible.sync="deliveryNoteOpen"
+      center
+      title="批量发货"
+      width="35%"
+    >
+      <span slot="footer" class="dialog-footer">
+        <!-- 小程序Appid选择 -->
+        <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
+          <el-form-item label="小程序:" prop="miniAppId">
+        <el-select
+          v-model="ruleForm.miniAppId"
+          clearable
+          placeholder="请选择发货小程序"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="item in miniAppList"
+            :key="item.appId"
+            :label="item.appName"
+            :value="item.appId"
+          />
+        </el-select>
+      </el-form-item>
+        </el-form>
+
+        <el-upload ref="upload" :action="uploadUrl" :auto-upload="false" :disabled="orderUpload.isUploading" :headers="orderUpload.headers"
+                   :limit="1" :on-progress="handleFileUploadProgress"
+                   :on-success="handleFileSuccess" accept=".xlsx, .xls" drag
+        >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">
+          将文件拖到此处,或
+          <em>点击上传</em>
+        </div>
+        <div slot="tip" class="el-upload__tip">
+          <el-link style="font-size:12px" type="info" @click="importDeliveryNoteTemplate">下载模板</el-link>
+        </div>
+        <div slot="tip" class="el-upload__tip" style="color:red">提示:仅允许导入“xls”或“xlsx”格式文件!</div>
+      </el-upload>
+        <el-divider></el-divider>
+        <el-button @click="cancelResetDeliveryNote">取 消</el-button>
+        <el-button type="primary" @click="submitDeliveryNote('ruleForm')">确 定</el-button>
+      </span>
+    </el-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
 <script>
 <script>
-import { listLiveOrderZm, exportLiveOrderZm } from "@/api/live/liveOrder";
+import { listLiveOrderZm, exportLiveOrderZm,healthExportShippingOrder,importDeliveryNoteExpressTemplate } from "@/api/live/liveOrder";
 import liveOrderDetails from './liveOrderDetails.vue';
 import liveOrderDetails from './liveOrderDetails.vue';
 import {getCompanyList} from "@/api/company/company";
 import {getCompanyList} from "@/api/company/company";
 import Treeselect from "@riophae/vue-treeselect";
 import Treeselect from "@riophae/vue-treeselect";
 import {treeselect} from "@/api/company/companyDept";
 import {treeselect} from "@/api/company/companyDept";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import { getToken } from '@/utils/auth'
 import {parseTime} from "../../../utils/common";
 import {parseTime} from "../../../utils/common";
 
 
 export default {
 export default {
@@ -234,6 +301,34 @@ export default {
   components: {Treeselect, liveOrderDetails },
   components: {Treeselect, liveOrderDetails },
   data() {
   data() {
     return {
     return {
+      upload: {
+        // 是否显示弹出层(用户导入)
+        open: false,
+        // 弹出层标题(用户导入)
+        title: '',
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: 'Bearer ' + getToken() },
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + '/live/liveOrder/importExpress'
+      },
+      orderUpload: {
+        // 是否显示弹出层(用户导入)
+        open: false,
+        // 弹出层标题(用户导入)
+        title: '',
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: 'Bearer ' + getToken() },
+      },
+      deliveryNoteOpen: false,
+      miniAppList: [],
       // 字典
       // 字典
       orderStatusOptions: [],
       orderStatusOptions: [],
       memberLevelOptions: [],
       memberLevelOptions: [],
@@ -282,12 +377,26 @@ export default {
         orderEndTime: null,
         orderEndTime: null,
         status: null,
         status: null,
       },
       },
+      ruleForm:{
+        miniAppId: null,
+      },
       orderOptions: [],
       orderOptions: [],
       actName: "10",
       actName: "10",
       show: {
       show: {
         title: "订单详情",
         title: "订单详情",
         open: false,
         open: false,
       },
       },
+      rules: {
+        userId: [
+          { required: true, message: '会员信息不能为空' }
+        ],
+        addressId: [
+          { required: true, message: '收货信息不能为空' }
+        ],
+        miniAppId: [
+          { required: true, message: '发货小程序不能为空' }
+        ],
+      },
     };
     };
   },
   },
   created() {
   created() {
@@ -313,8 +422,59 @@ export default {
       this.customerStatusOptions = response.data;
       this.customerStatusOptions = response.data;
     });
     });
   },
   },
+  computed: {
+
+    uploadUrl() {
+      return process.env.VUE_APP_BASE_API +
+        '/live/liveOrder/importDeliveryNoteExpress?miniAppId=' +
+        this.ruleForm.miniAppId;
+    }
+  },
   methods: {
   methods: {
-    parseTime,
+    // 提交发货单
+    submitDeliveryNote(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          const uploadFiles = this.$refs.upload.uploadFiles
+          if (uploadFiles.length === 0) {
+            this.$message.error('请选择要上传的文件')
+            return
+          }
+          this.$refs.upload.submit()
+        } else {
+          return false
+        }
+      })
+    },
+    //发货单模板下载
+    importDeliveryNoteTemplate() {
+      importDeliveryNoteExpressTemplate().then((response) => {
+        this.download(response.msg)
+      })
+    },
+    handleFileSuccess(response, file, fileList) {
+      this.upload.open = false
+      this.upload.isUploading = false
+      this.$refs.upload.clearFiles()
+      this.importMsgOpen = true
+      this.importMsg = response.msg
+      // this.$alert(response.msg, '导入结果', {
+      //     dangerouslyUseHTMLString: true
+      //   });
+      this.getList()
+    },
+    // 文件上传中处理
+    handleFileUploadProgress(event, file, fileList) {
+      this.upload.isUploading = true
+    },
+    handleClose(done) {
+      this.$confirm('确认关闭?')
+        .then(_ => {
+          done()
+        })
+        .catch(_ => {
+        })
+    },
 
 
     // 下单时间范围选择变化处理
     // 下单时间范围选择变化处理
     handleOrderTimeChange(value) {
     handleOrderTimeChange(value) {
@@ -419,6 +579,52 @@ export default {
       this.queryParams.deptId = val;
       this.queryParams.deptId = val;
       this.getList();
       this.getList();
     },
     },
+    handleExportShippingOrder() {
+      if (this.queryParams.status == '00') {
+        this.queryParams.status = null
+      }
+      if (this.createTimeRange != null && this.createTimeRange.length == 2) {
+        this.queryParams.createTimeRange = this.createTimeRange[0] + '--' + this.createTimeRange[1]
+      } else {
+        this.queryParams.createTimeRange = null
+      }
+      if (this.payTimeRange != null && this.payTimeRange.length == 2) {
+        this.queryParams.payTimeRange = this.payTimeRange[0] + '--' + this.payTimeRange[1]
+      } else {
+        this.queryParams.payTimeRange = null
+      }
+      if (this.deliveryImportTimeRange != null && this.deliveryImportTimeRange.length == 2) {
+        this.queryParams.deliveryImportTimeRange = this.deliveryImportTimeRange[0] + '--' + this.deliveryImportTimeRange[1]
+      } else {
+        this.queryParams.deliveryImportTimeRange = null
+      }
+      if (this.deliverySendTimeRange != null && this.deliverySendTimeRange.length == 2) {
+        this.queryParams.deliverySendTimeRange = this.deliverySendTimeRange[0] + '--' + this.deliverySendTimeRange[1]
+      } else {
+        this.queryParams.deliverySendTimeRange = null
+      }
+      const queryParams = this.addDateRange(this.queryParams, this.dateRange)
+      this.$confirm('是否确认导出所有订单明细数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return healthExportShippingOrder(queryParams)
+      }).then(response => {
+        this.download(response.msg)
+      }).catch(function() {
+      })
+    },
+    //打开发货单
+    openDeliveryNote() {
+      this.deliveryNoteOpen = true
+      this.getAppList();
+    },
+    //取消重置
+    cancelResetDeliveryNote(){
+      this.deliveryNoteOpen = false;
+      this.resetForm('ruleForm')
+    },
   }
   }
 };
 };
 </script>
 </script>