|
|
@@ -1,10 +1,443 @@
|
|
|
<template>
|
|
|
- <view> aaaaa </view>
|
|
|
+ <view class="report-page">
|
|
|
+ <scroll-view class="report-scroll" scroll-y>
|
|
|
+ <view v-if="loading" class="state-card">
|
|
|
+ <text class="state-text">数据加载中...</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view v-else-if="!dataList.length" class="state-card empty">
|
|
|
+ <text class="state-text">当前日期暂无数据</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view v-else class="report-list">
|
|
|
+ <view
|
|
|
+ v-for="(item, index) in dataList"
|
|
|
+ :key="index"
|
|
|
+ class="report-card"
|
|
|
+ >
|
|
|
+ <!-- 基本信息 -->
|
|
|
+ <view class="card-header">
|
|
|
+ <view class="header-left">
|
|
|
+ <text class="company-name">{{
|
|
|
+ item.projectClassification || "--"
|
|
|
+ }}</text>
|
|
|
+ <text class="project-name">{{ item.projectName || "--" }}</text>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ class="status-badge"
|
|
|
+ :class="getStatusClass(item.constructionStatusName)"
|
|
|
+ >
|
|
|
+ {{ item.constructionStatusName || "--" }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 队伍和任务 -->
|
|
|
+ <view class="info-row">
|
|
|
+ <view class="info-item">
|
|
|
+ <text class="info-label">队伍</text>
|
|
|
+ <text class="info-value">{{ item.deptName || "--" }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="info-item">
|
|
|
+ <text class="info-label">生产任务</text>
|
|
|
+ <text class="info-value">{{ item.taskName || "--" }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 核心指标 -->
|
|
|
+ <view class="metrics-grid">
|
|
|
+ <view class="metric-item">
|
|
|
+ <text class="metric-label">当日进尺/井次</text>
|
|
|
+ <text class="metric-value">{{ formatFootageOrWell(item) }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="metric-item">
|
|
|
+ <text class="metric-label">当日电耗</text>
|
|
|
+ <text class="metric-value"
|
|
|
+ >{{ formatNumber(item.dailyPowerUsage) }}kWh</text
|
|
|
+ >
|
|
|
+ </view>
|
|
|
+ <view class="metric-item">
|
|
|
+ <text class="metric-label">当日油耗</text>
|
|
|
+ <text class="metric-value"
|
|
|
+ >{{ formatNumber(item.dailyFuel) }}L</text
|
|
|
+ >
|
|
|
+ </view>
|
|
|
+ <view class="metric-item">
|
|
|
+ <text class="metric-label">非生产时间</text>
|
|
|
+ <text class="metric-value"
|
|
|
+ >{{ formatNumber(item.nonProductionTime) }}h</text
|
|
|
+ >
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 下步任务 -->
|
|
|
+ <view class="desc-panel" v-if="item.nextPlan">
|
|
|
+ <view class="desc-title">下步任务</view>
|
|
|
+ <text class="desc-text">{{ item.nextPlan }}</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 当日生产简况 -->
|
|
|
+ <view class="desc-panel" v-if="item.constructionBrief">
|
|
|
+ <view class="desc-title">当日生产简况</view>
|
|
|
+ <text class="desc-text">{{ item.constructionBrief }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+
|
|
|
+ <!-- 筛选栏 -->
|
|
|
+ <view class="filter-bar">
|
|
|
+ <view class="filter-main">
|
|
|
+ <text class="filter-label">日期</text>
|
|
|
+ <uni-datetime-picker
|
|
|
+ v-model="selectedDate"
|
|
|
+ class="date-picker"
|
|
|
+ type="date"
|
|
|
+ :teleport="true"
|
|
|
+ return-type="string"
|
|
|
+ :clear-icon="false"
|
|
|
+ :border="false"
|
|
|
+ @change="handleDateChange"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <button
|
|
|
+ class="filter-button"
|
|
|
+ type="primary"
|
|
|
+ size="mini"
|
|
|
+ @click="loadList"
|
|
|
+ >
|
|
|
+ 查询
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { computed, ref } from "vue";
|
|
|
-import { onMounted } from "vue";
|
|
|
+import { ref, onMounted } from "vue";
|
|
|
import dayjs from "dayjs";
|
|
|
-import { getRyProductionBriefs } from "@/api/ruiYingReport"; // 列表接口
|
|
|
+// 假设接口地址为 getRyProductionBriefs,请根据实际接口调整
|
|
|
+import { getRyProductionBriefs } from "@/api/ruiYingReport";
|
|
|
+
|
|
|
+// 状态
|
|
|
+const selectedDate = ref(dayjs().subtract(1, "day").format("YYYY-MM-DD"));
|
|
|
+const dataList = ref([]);
|
|
|
+const loading = ref(false);
|
|
|
+
|
|
|
+// 构建查询参数
|
|
|
+const buildQueryParams = () => {
|
|
|
+ const baseDate = selectedDate.value
|
|
|
+ ? dayjs(selectedDate.value)
|
|
|
+ : dayjs().subtract(1, "day");
|
|
|
+
|
|
|
+ return {
|
|
|
+ createTime: [
|
|
|
+ baseDate.startOf("day").format("YYYY-MM-DD HH:mm:ss"),
|
|
|
+ baseDate.endOf("day").format("YYYY-MM-DD HH:mm:ss"),
|
|
|
+ ],
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+// 格式化数字
|
|
|
+const formatNumber = (value, fractionDigits = 1) => {
|
|
|
+ if (value === null || value === undefined || value === "") return "--";
|
|
|
+ const numberValue = Number(value);
|
|
|
+ if (isNaN(numberValue)) return "--";
|
|
|
+ if (Number.isInteger(numberValue)) {
|
|
|
+ return `${numberValue}`;
|
|
|
+ }
|
|
|
+ return numberValue.toFixed(fractionDigits);
|
|
|
+};
|
|
|
+
|
|
|
+// 格式化进尺/井次
|
|
|
+const formatFootageOrWell = (row) => {
|
|
|
+ if (!row) return "--";
|
|
|
+ if (row.projectClassification === "钻井") {
|
|
|
+ const footage = formatNumber(row.dailyFootage);
|
|
|
+ return footage === "--" ? "--" : `${footage}m`;
|
|
|
+ }
|
|
|
+ return formatNumber(row.completedWells, 0);
|
|
|
+};
|
|
|
+
|
|
|
+// 获取状态样式
|
|
|
+const getStatusClass = (status) => {
|
|
|
+ if (!status) return "";
|
|
|
+ const statusMap = {
|
|
|
+ 施工中: "status-construction",
|
|
|
+ 待命: "status-standby",
|
|
|
+ 停工: "status-stopped",
|
|
|
+ 完工: "status-completed",
|
|
|
+ 准备: "status-ready",
|
|
|
+ };
|
|
|
+ return statusMap[status] || "";
|
|
|
+};
|
|
|
+
|
|
|
+// 加载数据
|
|
|
+const loadList = async () => {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ const response = await getRyProductionBriefs(buildQueryParams());
|
|
|
+ dataList.value = Array.isArray(response?.data) ? response.data : [];
|
|
|
+ } catch (error) {
|
|
|
+ dataList.value = [];
|
|
|
+ uni.showToast({
|
|
|
+ title: "数据加载失败",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 日期变化处理
|
|
|
+const handleDateChange = () => {
|
|
|
+ loadList();
|
|
|
+};
|
|
|
+
|
|
|
+// 生命周期
|
|
|
+onMounted(() => {
|
|
|
+ loadList();
|
|
|
+});
|
|
|
</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.report-page {
|
|
|
+ max-height: 100vh;
|
|
|
+ padding: 12px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+// 筛选栏
|
|
|
+.filter-bar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 14px;
|
|
|
+ border-radius: 18px;
|
|
|
+ background: rgba(255, 255, 255, 0.94);
|
|
|
+ box-shadow: 0 14px 32px rgba(25, 56, 104, 0.08);
|
|
|
+ backdrop-filter: blur(10px);
|
|
|
+}
|
|
|
+
|
|
|
+.filter-main {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 10rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-label {
|
|
|
+ display: block;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ color: #5f6f87;
|
|
|
+ font-size: 12px;
|
|
|
+ letter-spacing: 1px;
|
|
|
+}
|
|
|
+
|
|
|
+.date-picker {
|
|
|
+ padding: 0 12px;
|
|
|
+ border: 1px solid rgba(0, 64, 152, 0.1);
|
|
|
+ border-radius: 12px;
|
|
|
+ background: #f8fbff;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-button {
|
|
|
+ width: 76px;
|
|
|
+ height: 38px;
|
|
|
+ line-height: 40px;
|
|
|
+ border-radius: 12px;
|
|
|
+ background: linear-gradient(135deg, #004098 0%, #1f68d8 100%);
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+// 滚动区域
|
|
|
+.report-scroll {
|
|
|
+ height: calc(100vh - 140px);
|
|
|
+ padding-top: 12px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+// 列表
|
|
|
+.report-list {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 14px;
|
|
|
+ padding-bottom: 18px;
|
|
|
+}
|
|
|
+
|
|
|
+// 卡片
|
|
|
+.report-card {
|
|
|
+ padding: 16px;
|
|
|
+ border: 1px solid rgba(0, 64, 152, 0.08);
|
|
|
+ border-radius: 20px;
|
|
|
+ background: rgba(255, 255, 255, 0.96);
|
|
|
+ box-shadow: 0 18px 38px rgba(31, 57, 90, 0.08);
|
|
|
+}
|
|
|
+
|
|
|
+// 头部
|
|
|
+.card-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 12px;
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.header-left {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 4px;
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.company-name {
|
|
|
+ color: #122033;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 700;
|
|
|
+ line-height: 26px;
|
|
|
+}
|
|
|
+
|
|
|
+.project-name {
|
|
|
+ color: #5f6f87;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+// 状态标签
|
|
|
+.status-badge {
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 4px 14px;
|
|
|
+ border-radius: 999px;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 600;
|
|
|
+ text-align: center;
|
|
|
+ background: #f0f2f5;
|
|
|
+ color: #5f6f87;
|
|
|
+}
|
|
|
+
|
|
|
+.status-construction {
|
|
|
+ background: #e6f7e6;
|
|
|
+ color: #52c41a;
|
|
|
+}
|
|
|
+
|
|
|
+.status-standby {
|
|
|
+ background: #fff7e6;
|
|
|
+ color: #faad14;
|
|
|
+}
|
|
|
+
|
|
|
+.status-stopped {
|
|
|
+ background: #fde6e6;
|
|
|
+ color: #ff4d4f;
|
|
|
+}
|
|
|
+
|
|
|
+.status-completed {
|
|
|
+ background: #e6f0ff;
|
|
|
+ color: #1890ff;
|
|
|
+}
|
|
|
+
|
|
|
+.status-ready {
|
|
|
+ background: #f0f0f0;
|
|
|
+ color: #8c8c8c;
|
|
|
+}
|
|
|
+
|
|
|
+// 信息行
|
|
|
+.info-row {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr 1fr;
|
|
|
+ gap: 8px 16px;
|
|
|
+ padding: 12px 0;
|
|
|
+ border-top: 1px solid #f0f2f5;
|
|
|
+ border-bottom: 1px solid #f0f2f5;
|
|
|
+}
|
|
|
+
|
|
|
+.info-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.info-label {
|
|
|
+ color: #6d7c91;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.info-value {
|
|
|
+ color: #17253a;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+// 指标网格
|
|
|
+.metrics-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(2, 1fr);
|
|
|
+ gap: 10px;
|
|
|
+ padding: 12px 0;
|
|
|
+ border-bottom: 1px solid #f0f2f5;
|
|
|
+}
|
|
|
+
|
|
|
+.metric-item {
|
|
|
+ padding: 12px;
|
|
|
+ border-radius: 14px;
|
|
|
+ background: #f6f9fd;
|
|
|
+}
|
|
|
+
|
|
|
+.metric-label {
|
|
|
+ display: block;
|
|
|
+ color: #6e7e95;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.metric-value {
|
|
|
+ display: block;
|
|
|
+ margin-top: 6px;
|
|
|
+ color: #18273b;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+
|
|
|
+// 描述面板
|
|
|
+.desc-panel {
|
|
|
+ padding-top: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.desc-panel + .desc-panel {
|
|
|
+ border-top: 1px solid #f0f2f5;
|
|
|
+ padding-top: 14px;
|
|
|
+ margin-top: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.desc-title {
|
|
|
+ margin-bottom: 6px;
|
|
|
+ color: #1f2f46;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+
|
|
|
+.desc-text {
|
|
|
+ color: #5f6f87;
|
|
|
+ font-size: 13px;
|
|
|
+ line-height: 22px;
|
|
|
+ white-space: pre-wrap;
|
|
|
+}
|
|
|
+
|
|
|
+// 空状态
|
|
|
+.state-card {
|
|
|
+ margin-top: 18px;
|
|
|
+ padding: 40px 20px;
|
|
|
+ border-radius: 18px;
|
|
|
+ background: rgba(255, 255, 255, 0.92);
|
|
|
+ text-align: center;
|
|
|
+ box-shadow: 0 12px 28px rgba(30, 54, 88, 0.06);
|
|
|
+}
|
|
|
+
|
|
|
+.state-card.empty {
|
|
|
+ border: 1px dashed rgba(0, 64, 152, 0.16);
|
|
|
+}
|
|
|
+
|
|
|
+.state-text {
|
|
|
+ color: #73839a;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+</style>
|