| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // è½èç±»å |
| | | import request from "@/utils/request"; |
| | | |
| | | // è½èç±»å-å页æ¥è¯¢ |
| | | export function energyTypeListPage(query) { |
| | | return request({ |
| | | url: "/energy/page", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | // è½èç±»å-æ°å¢ä¿®æ¹ |
| | | export function energyTypeAdd(query) { |
| | | return request({ |
| | | url: "/energy", |
| | | method: "post", |
| | | data: query, |
| | | }); |
| | | } |
| | | |
| | | // è½èç±»å-å é¤ |
| | | export function energyTypeDelete(ids) { |
| | | return request({ |
| | | url: "/energy/" + ids, |
| | | method: "delete", |
| | | }); |
| | | } |
| | | |
| | | // è½èæè¡¨æç» |
| | | export function energyConsumptionDetailListPage(query) { |
| | | return request({ |
| | | url: "/energyConsumptionDetail/page", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | // è½èæè¡¨æç»-æ°å¢ä¿®æ¹ |
| | | export function energyConsumptionDetailAdd(query) { |
| | | return request({ |
| | | url: "/energyConsumptionDetail", |
| | | method: "post", |
| | | data: query, |
| | | }); |
| | | } |
| | | |
| | | |
| | | // è½èæè¡¨æç»-å é¤ |
| | | export function energyConsumptionDetailDelete(ids) { |
| | | return request({ |
| | | url: "/energyConsumptionDetail/" + ids, |
| | | method: "delete", |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // ç产订å页颿¥å£ |
| | | import request from "@/utils/request"; |
| | | |
| | | |
| | | export function productionPlanListPage(query) { |
| | | return request({ |
| | | url: "/productionPlan/listPage", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- æç´¢åºå --> |
| | | <div class="search_form"> |
| | | <el-form :model="searchForm" |
| | | :inline="true"> |
| | | <el-form-item label="ç»è®¡ç»´åº¦:"> |
| | | <el-radio-group v-model="statisticsType" |
| | | @change="handleTypeChange"> |
| | | <el-radio-button label="day">ææ¥ç»è®¡</el-radio-button> |
| | | <el-radio-button label="month">ææç»è®¡</el-radio-button> |
| | | <el-radio-button label="year">æå¹´ç»è®¡</el-radio-button> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="è½èç¨é:"> |
| | | <el-select v-model="searchForm.energyType" |
| | | placeholder="å
¨é¨" |
| | | clearable |
| | | style="width: 120px;" |
| | | @change="handleQuery"> |
| | | <el-option label="å
¨é¨" |
| | | value="å
¨é¨" /> |
| | | <el-option label="åå
¬" |
| | | value="åå
¬" /> |
| | | <el-option label="ç产" |
| | | value="ç产" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ¶é´èå´:"> |
| | | <el-date-picker v-if="statisticsType === 'day'" |
| | | v-model="searchForm.dateRange" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 240px;" |
| | | @change="handleQuery" /> |
| | | <el-date-picker v-else-if="statisticsType === 'month'" |
| | | v-model="searchForm.monthRange" |
| | | type="monthrange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æä»½" |
| | | end-placeholder="ç»ææä»½" |
| | | value-format="YYYY-MM" |
| | | style="width: 240px;" |
| | | @change="handleQuery" /> |
| | | <el-select v-else |
| | | v-model="searchForm.year" |
| | | placeholder="鿩年份" |
| | | style="width: 140px;" |
| | | @change="handleQuery"> |
| | | <el-option v-for="year in yearOptions" |
| | | :key="year" |
| | | :label="year + 'å¹´'" |
| | | :value="year" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery">æ¥è¯¢</el-button> |
| | | <el-button @click="handleReset">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div> |
| | | <el-button type="success" |
| | | @click="handleExport">å¯¼åºæ¥è¡¨</el-button> |
| | | </div> |
| | | </div> |
| | | <!-- ç»è®¡æ¦è§å¡ç --> |
| | | <div class="statistics-overview"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="6"> |
| | | <div class="overview-card total-consumption"> |
| | | <div class="overview-icon"> |
| | | <el-icon> |
| | | <DataLine /> |
| | | </el-icon> |
| | | </div> |
| | | <div class="overview-info"> |
| | | <div class="overview-label">æ»è½èç¨é</div> |
| | | <div class="overview-value">{{ overview.totalConsumption }} <span class="unit">å¨/度/m³</span></div> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <div class="overview-card total-amount"> |
| | | <div class="overview-icon"> |
| | | <el-icon> |
| | | <Money /> |
| | | </el-icon> |
| | | </div> |
| | | <div class="overview-info"> |
| | | <div class="overview-label">æ»è½èè´¹ç¨</div> |
| | | <div class="overview-value">Â¥{{ overview.totalAmount }}</div> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <div class="overview-card avg-consumption"> |
| | | <div class="overview-icon"> |
| | | <el-icon> |
| | | <TrendCharts /> |
| | | </el-icon> |
| | | </div> |
| | | <div class="overview-info"> |
| | | <div class="overview-label">å¹³åç¨é</div> |
| | | <div class="overview-value">{{ overview.avgConsumption }} <span class="unit">/{{ statisticsType === 'day' ? 'æ¥' : statisticsType === 'month' ? 'æ' : 'å¹´' }}</span></div> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <div class="overview-card compare-last"> |
| | | <div class="overview-icon"> |
| | | <el-icon> |
| | | <Histogram /> |
| | | </el-icon> |
| | | </div> |
| | | <div class="overview-info"> |
| | | <div class="overview-label">ç¯æ¯åå</div> |
| | | <div class="overview-value" |
| | | :class="overview.compareRate >= 0 ? 'up' : 'down'"> |
| | | <el-icon v-if="overview.compareRate >= 0"> |
| | | <ArrowUp /> |
| | | </el-icon> |
| | | <el-icon v-else> |
| | | <ArrowDown /> |
| | | </el-icon> |
| | | {{ Math.abs(overview.compareRate) }}% |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <!-- å¾è¡¨åºå --> |
| | | <div class="charts-container"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <div class="chart-card"> |
| | | <div class="chart-title">è½èç¨éè¶å¿</div> |
| | | <div ref="consumptionChart" |
| | | class="chart-content"></div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="chart-card"> |
| | | <div class="chart-title">è½èè´¹ç¨è¶å¿</div> |
| | | <div ref="amountChart" |
| | | class="chart-content"></div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20" |
| | | style="margin-top: 20px;"> |
| | | <el-col :span="12"> |
| | | <div class="chart-card"> |
| | | <div class="chart-title">è½èç±»åå æ¯</div> |
| | | <div ref="typeChart" |
| | | class="chart-content"></div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="chart-card"> |
| | | <div class="chart-title">è½èç±»åè´¹ç¨å æ¯</div> |
| | | <div ref="amountTypeChart" |
| | | class="chart-content"></div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <!-- æ°æ®è¡¨æ ¼ --> |
| | | <div class="table-section"> |
| | | <div class="section-title">è¯¦ç»æ°æ®</div> |
| | | <el-table :data="tableData" |
| | | v-loading="tableLoading" |
| | | border |
| | | stripe> |
| | | <el-table-column type="index" |
| | | label="åºå·" |
| | | width="60" |
| | | align="center" /> |
| | | <el-table-column prop="timePeriod" |
| | | :label="timeColumnLabel" |
| | | align="center" /> |
| | | <el-table-column prop="waterConsumption" |
| | | label="ç¨æ°´é(å¨)" |
| | | align="right"> |
| | | <template #default="scope"> |
| | | <span class="consumption-value">{{ scope.row.waterConsumption }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="waterAmount" |
| | | label="æ°´è´¹(å
)" |
| | | align="right"> |
| | | <template #default="scope"> |
| | | <span class="amount-value">{{ scope.row.waterAmount }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="electricityConsumption" |
| | | label="ç¨çµé(度)" |
| | | align="right"> |
| | | <template #default="scope"> |
| | | <span class="consumption-value">{{ scope.row.electricityConsumption }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="electricityAmount" |
| | | label="çµè´¹(å
)" |
| | | align="right"> |
| | | <template #default="scope"> |
| | | <span class="amount-value">{{ scope.row.electricityAmount }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="gasConsumption" |
| | | label="ç¨æ°é(m³)" |
| | | align="right"> |
| | | <template #default="scope"> |
| | | <span class="consumption-value">{{ scope.row.gasConsumption }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="gasAmount" |
| | | label="æ°è´¹(å
)" |
| | | align="right"> |
| | | <template #default="scope"> |
| | | <span class="amount-value">{{ scope.row.gasAmount }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="totalConsumption" |
| | | label="å计ç¨é" |
| | | align="right"> |
| | | <template #default="scope"> |
| | | <span class="total-value">{{ scope.row.totalConsumption }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="totalAmount" |
| | | label="å计费ç¨(å
)" |
| | | align="right" |
| | | fixed="right"> |
| | | <template #default="scope"> |
| | | <span class="total-amount-value">Â¥{{ scope.row.totalAmount }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | <!-- å页 --> |
| | | <div class="pagination-container"> |
| | | <el-pagination v-model:current-page="page.current" |
| | | v-model:page-size="page.size" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :total="page.total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, computed, nextTick } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { |
| | | DataLine, |
| | | Money, |
| | | TrendCharts, |
| | | Histogram, |
| | | ArrowUp, |
| | | ArrowDown, |
| | | } from "@element-plus/icons-vue"; |
| | | import * as echarts from "echarts"; |
| | | |
| | | // ç»è®¡ç»´åº¦ï¼day-ææ¥ï¼month-ææï¼year-æå¹´ |
| | | const statisticsType = ref("day"); |
| | | |
| | | // æç´¢è¡¨å |
| | | const searchForm = reactive({ |
| | | energyType: "", |
| | | dateRange: [], |
| | | monthRange: [], |
| | | year: new Date().getFullYear(), |
| | | }); |
| | | |
| | | // 年份é项 |
| | | const yearOptions = computed(() => { |
| | | const currentYear = new Date().getFullYear(); |
| | | const years = []; |
| | | for (let i = currentYear - 5; i <= currentYear; i++) { |
| | | years.push(i); |
| | | } |
| | | return years.reverse(); |
| | | }); |
| | | |
| | | // æ¶é´åæ ç¾ |
| | | const timeColumnLabel = computed(() => { |
| | | const labels = { |
| | | day: "æ¥æ", |
| | | month: "æä»½", |
| | | year: "年份", |
| | | }; |
| | | return labels[statisticsType.value]; |
| | | }); |
| | | |
| | | // ç»è®¡æ¦è§ |
| | | const overview = reactive({ |
| | | totalConsumption: "25,680.5", |
| | | totalAmount: "45,280.60", |
| | | avgConsumption: "856.0", |
| | | compareRate: -5.2, |
| | | }); |
| | | |
| | | // è¡¨æ ¼æ°æ® |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | |
| | | // å页 |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | total: 0, |
| | | }); |
| | | |
| | | // å¾è¡¨å¼ç¨ |
| | | const consumptionChart = ref(null); |
| | | const amountChart = ref(null); |
| | | const typeChart = ref(null); |
| | | const amountTypeChart = ref(null); |
| | | |
| | | // å¾è¡¨å®ä¾ |
| | | let consumptionChartInstance = null; |
| | | let amountChartInstance = null; |
| | | let typeChartInstance = null; |
| | | let amountTypeChartInstance = null; |
| | | |
| | | // çææ¨¡ææ°æ® |
| | | const generateMockData = () => { |
| | | const data = []; |
| | | const count = |
| | | statisticsType.value === "day" |
| | | ? 30 |
| | | : statisticsType.value === "month" |
| | | ? 12 |
| | | : 5; |
| | | |
| | | for (let i = 0; i < count; i++) { |
| | | const waterConsumption = (Math.random() * 100 + 50).toFixed(2); |
| | | const waterAmount = (waterConsumption * 2.5).toFixed(2); |
| | | const electricityConsumption = (Math.random() * 500 + 200).toFixed(2); |
| | | const electricityAmount = (electricityConsumption * 0.8).toFixed(2); |
| | | const gasConsumption = (Math.random() * 200 + 100).toFixed(2); |
| | | const gasAmount = (gasConsumption * 3.0).toFixed(2); |
| | | |
| | | let timePeriod; |
| | | if (statisticsType.value === "day") { |
| | | const date = new Date(); |
| | | date.setDate(date.getDate() - i); |
| | | timePeriod = date.toISOString().split("T")[0]; |
| | | } else if (statisticsType.value === "month") { |
| | | const date = new Date(); |
| | | date.setMonth(date.getMonth() - i); |
| | | timePeriod = date.toISOString().slice(0, 7); |
| | | } else { |
| | | timePeriod = (new Date().getFullYear() - i).toString(); |
| | | } |
| | | |
| | | data.push({ |
| | | timePeriod, |
| | | waterConsumption, |
| | | waterAmount, |
| | | electricityConsumption, |
| | | electricityAmount, |
| | | gasConsumption, |
| | | gasAmount, |
| | | totalConsumption: ( |
| | | parseFloat(waterConsumption) + |
| | | parseFloat(electricityConsumption) + |
| | | parseFloat(gasConsumption) |
| | | ).toFixed(2), |
| | | totalAmount: ( |
| | | parseFloat(waterAmount) + |
| | | parseFloat(electricityAmount) + |
| | | parseFloat(gasAmount) |
| | | ).toFixed(2), |
| | | }); |
| | | } |
| | | return data.reverse(); |
| | | }; |
| | | |
| | | // åå§åå¾è¡¨ |
| | | const initCharts = () => { |
| | | nextTick(() => { |
| | | // è½èç¨éè¶å¿å¾ |
| | | if (consumptionChart.value) { |
| | | consumptionChartInstance = echarts.init(consumptionChart.value); |
| | | updateConsumptionChart(); |
| | | } |
| | | // è½èè´¹ç¨è¶å¿å¾ |
| | | if (amountChart.value) { |
| | | amountChartInstance = echarts.init(amountChart.value); |
| | | updateAmountChart(); |
| | | } |
| | | // è½èç±»åå æ¯å¾ |
| | | if (typeChart.value) { |
| | | typeChartInstance = echarts.init(typeChart.value); |
| | | updateTypeChart(); |
| | | } |
| | | // è½èç±»åè´¹ç¨å æ¯å¾ |
| | | if (amountTypeChart.value) { |
| | | amountTypeChartInstance = echarts.init(amountTypeChart.value); |
| | | updateAmountTypeChart(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // æ´æ°è½èç¨éè¶å¿å¾ |
| | | const updateConsumptionChart = () => { |
| | | const data = tableData.value; |
| | | const option = { |
| | | tooltip: { |
| | | trigger: "axis", |
| | | axisPointer: { type: "cross" }, |
| | | }, |
| | | legend: { |
| | | data: ["ç¨æ°´é", "ç¨çµé", "ç¨æ°é"], |
| | | bottom: 0, |
| | | }, |
| | | grid: { |
| | | left: "3%", |
| | | right: "4%", |
| | | bottom: "15%", |
| | | containLabel: true, |
| | | }, |
| | | xAxis: { |
| | | type: "category", |
| | | data: data.map(item => item.timePeriod), |
| | | axisLabel: { rotate: statisticsType.value === "day" ? 45 : 0 }, |
| | | }, |
| | | yAxis: { |
| | | type: "value", |
| | | name: "ç¨é", |
| | | }, |
| | | series: [ |
| | | { |
| | | name: "ç¨æ°´é", |
| | | type: "bar", |
| | | data: data.map(item => item.waterConsumption), |
| | | itemStyle: { color: "#409EFF" }, |
| | | }, |
| | | { |
| | | name: "ç¨çµé", |
| | | type: "bar", |
| | | data: data.map(item => item.electricityConsumption), |
| | | itemStyle: { color: "#E6A23C" }, |
| | | }, |
| | | { |
| | | name: "ç¨æ°é", |
| | | type: "bar", |
| | | data: data.map(item => item.gasConsumption), |
| | | itemStyle: { color: "#67C23A" }, |
| | | }, |
| | | ], |
| | | }; |
| | | consumptionChartInstance.setOption(option); |
| | | }; |
| | | |
| | | // æ´æ°è½èè´¹ç¨è¶å¿å¾ |
| | | const updateAmountChart = () => { |
| | | const data = tableData.value; |
| | | const option = { |
| | | tooltip: { |
| | | trigger: "axis", |
| | | axisPointer: { type: "cross" }, |
| | | }, |
| | | legend: { |
| | | data: ["æ°´è´¹", "çµè´¹", "æ°è´¹"], |
| | | bottom: 0, |
| | | }, |
| | | grid: { |
| | | left: "3%", |
| | | right: "4%", |
| | | bottom: "15%", |
| | | containLabel: true, |
| | | }, |
| | | xAxis: { |
| | | type: "category", |
| | | data: data.map(item => item.timePeriod), |
| | | axisLabel: { rotate: statisticsType.value === "day" ? 45 : 0 }, |
| | | }, |
| | | yAxis: { |
| | | type: "value", |
| | | name: "è´¹ç¨(å
)", |
| | | }, |
| | | series: [ |
| | | { |
| | | name: "æ°´è´¹", |
| | | type: "line", |
| | | data: data.map(item => item.waterAmount), |
| | | smooth: true, |
| | | itemStyle: { color: "#409EFF" }, |
| | | }, |
| | | { |
| | | name: "çµè´¹", |
| | | type: "line", |
| | | data: data.map(item => item.electricityAmount), |
| | | smooth: true, |
| | | itemStyle: { color: "#E6A23C" }, |
| | | }, |
| | | { |
| | | name: "æ°è´¹", |
| | | type: "line", |
| | | data: data.map(item => item.gasAmount), |
| | | smooth: true, |
| | | itemStyle: { color: "#67C23A" }, |
| | | }, |
| | | ], |
| | | }; |
| | | amountChartInstance.setOption(option); |
| | | }; |
| | | |
| | | // æ´æ°è½èç±»åå æ¯å¾ |
| | | const updateTypeChart = () => { |
| | | const data = tableData.value; |
| | | const totalWater = data.reduce( |
| | | (sum, item) => sum + parseFloat(item.waterConsumption), |
| | | 0 |
| | | ); |
| | | const totalElectricity = data.reduce( |
| | | (sum, item) => sum + parseFloat(item.electricityConsumption), |
| | | 0 |
| | | ); |
| | | const totalGas = data.reduce( |
| | | (sum, item) => sum + parseFloat(item.gasConsumption), |
| | | 0 |
| | | ); |
| | | |
| | | const option = { |
| | | tooltip: { |
| | | trigger: "item", |
| | | formatter: "{a} <br/>{b}: {c} ({d}%)", |
| | | }, |
| | | legend: { |
| | | orient: "vertical", |
| | | left: "left", |
| | | }, |
| | | series: [ |
| | | { |
| | | name: "è½èç¨é", |
| | | type: "pie", |
| | | radius: ["40%", "70%"], |
| | | avoidLabelOverlap: false, |
| | | itemStyle: { |
| | | borderRadius: 10, |
| | | borderColor: "#fff", |
| | | borderWidth: 2, |
| | | }, |
| | | label: { |
| | | show: true, |
| | | formatter: "{b}: {d}%", |
| | | }, |
| | | data: [ |
| | | { |
| | | value: totalWater.toFixed(2), |
| | | name: "æ°´", |
| | | itemStyle: { color: "#409EFF" }, |
| | | }, |
| | | { |
| | | value: totalElectricity.toFixed(2), |
| | | name: "çµ", |
| | | itemStyle: { color: "#E6A23C" }, |
| | | }, |
| | | { |
| | | value: totalGas.toFixed(2), |
| | | name: "æ°", |
| | | itemStyle: { color: "#67C23A" }, |
| | | }, |
| | | ], |
| | | }, |
| | | ], |
| | | }; |
| | | typeChartInstance.setOption(option); |
| | | }; |
| | | |
| | | // æ´æ°è½èç±»åè´¹ç¨å æ¯å¾ |
| | | const updateAmountTypeChart = () => { |
| | | const data = tableData.value; |
| | | const totalWaterAmount = data.reduce( |
| | | (sum, item) => sum + parseFloat(item.waterAmount), |
| | | 0 |
| | | ); |
| | | const totalElectricityAmount = data.reduce( |
| | | (sum, item) => sum + parseFloat(item.electricityAmount), |
| | | 0 |
| | | ); |
| | | const totalGasAmount = data.reduce( |
| | | (sum, item) => sum + parseFloat(item.gasAmount), |
| | | 0 |
| | | ); |
| | | |
| | | const option = { |
| | | tooltip: { |
| | | trigger: "item", |
| | | formatter: "{a} <br/>{b}: ¥{c} ({d}%)", |
| | | }, |
| | | legend: { |
| | | orient: "vertical", |
| | | left: "left", |
| | | }, |
| | | series: [ |
| | | { |
| | | name: "è½èè´¹ç¨", |
| | | type: "pie", |
| | | radius: "60%", |
| | | data: [ |
| | | { |
| | | value: totalWaterAmount.toFixed(2), |
| | | name: "æ°´è´¹", |
| | | itemStyle: { color: "#409EFF" }, |
| | | }, |
| | | { |
| | | value: totalElectricityAmount.toFixed(2), |
| | | name: "çµè´¹", |
| | | itemStyle: { color: "#E6A23C" }, |
| | | }, |
| | | { |
| | | value: totalGasAmount.toFixed(2), |
| | | name: "æ°è´¹", |
| | | itemStyle: { color: "#67C23A" }, |
| | | }, |
| | | ], |
| | | emphasis: { |
| | | itemStyle: { |
| | | shadowBlur: 10, |
| | | shadowOffsetX: 0, |
| | | shadowColor: "rgba(0, 0, 0, 0.5)", |
| | | }, |
| | | }, |
| | | }, |
| | | ], |
| | | }; |
| | | amountTypeChartInstance.setOption(option); |
| | | }; |
| | | |
| | | // ç»è®¡ç»´åº¦åæ¢ |
| | | const handleTypeChange = () => { |
| | | // éç½®æ¶é´èå´ |
| | | searchForm.dateRange = []; |
| | | searchForm.monthRange = []; |
| | | searchForm.year = new Date().getFullYear(); |
| | | page.current = 1; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // æ¥è¯¢ |
| | | const handleQuery = () => { |
| | | tableLoading.value = true; |
| | | setTimeout(() => { |
| | | const data = generateMockData(); |
| | | tableData.value = data; |
| | | page.total = data.length; |
| | | tableLoading.value = false; |
| | | updateCharts(); |
| | | }, 300); |
| | | }; |
| | | |
| | | // æ´æ°ææå¾è¡¨ |
| | | const updateCharts = () => { |
| | | nextTick(() => { |
| | | if (consumptionChartInstance) updateConsumptionChart(); |
| | | if (amountChartInstance) updateAmountChart(); |
| | | if (typeChartInstance) updateTypeChart(); |
| | | if (amountTypeChartInstance) updateAmountTypeChart(); |
| | | }); |
| | | }; |
| | | |
| | | // éç½® |
| | | const handleReset = () => { |
| | | searchForm.energyType = ""; |
| | | searchForm.dateRange = []; |
| | | searchForm.monthRange = []; |
| | | searchForm.year = new Date().getFullYear(); |
| | | page.current = 1; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleExport = () => { |
| | | ElMessage.success("æ¥è¡¨å¯¼åºæå"); |
| | | }; |
| | | |
| | | // å页大å°åå |
| | | const handleSizeChange = val => { |
| | | page.size = val; |
| | | }; |
| | | |
| | | // 页ç åå |
| | | const handleCurrentChange = val => { |
| | | page.current = val; |
| | | }; |
| | | |
| | | // çªå£å¤§å°ååæ¶éæ°æ¸²æå¾è¡¨ |
| | | const handleResize = () => { |
| | | consumptionChartInstance && consumptionChartInstance.resize(); |
| | | amountChartInstance && amountChartInstance.resize(); |
| | | typeChartInstance && typeChartInstance.resize(); |
| | | amountTypeChartInstance && amountTypeChartInstance.resize(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | handleQuery(); |
| | | initCharts(); |
| | | window.addEventListener("resize", handleResize); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .app-container { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .search_form { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | padding: 15px; |
| | | background-color: #f5f7fa; |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .statistics-overview { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .overview-card { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 20px; |
| | | border-radius: 8px; |
| | | background: #fff; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | |
| | | &.total-consumption { |
| | | border-left: 4px solid #409eff; |
| | | } |
| | | |
| | | &.total-amount { |
| | | border-left: 4px solid #67c23a; |
| | | } |
| | | |
| | | &.avg-consumption { |
| | | border-left: 4px solid #e6a23c; |
| | | } |
| | | |
| | | &.compare-last { |
| | | border-left: 4px solid #909399; |
| | | } |
| | | |
| | | .overview-icon { |
| | | width: 50px; |
| | | height: 50px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background: #f5f7fa; |
| | | border-radius: 50%; |
| | | margin-right: 15px; |
| | | |
| | | .el-icon { |
| | | font-size: 24px; |
| | | color: #409eff; |
| | | } |
| | | } |
| | | |
| | | .overview-info { |
| | | flex: 1; |
| | | |
| | | .overview-label { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .overview-value { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | |
| | | .unit { |
| | | font-size: 14px; |
| | | font-weight: normal; |
| | | color: #909399; |
| | | } |
| | | |
| | | &.up { |
| | | color: #67c23a; |
| | | } |
| | | |
| | | &.down { |
| | | color: #f56c6c; |
| | | } |
| | | |
| | | .el-icon { |
| | | font-size: 16px; |
| | | vertical-align: middle; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .charts-container { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .chart-card { |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | padding: 20px; |
| | | |
| | | .chart-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | margin-bottom: 15px; |
| | | padding-bottom: 10px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .chart-content { |
| | | height: 300px; |
| | | } |
| | | } |
| | | |
| | | .table-section { |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | padding: 20px; |
| | | margin-bottom: 20px; |
| | | |
| | | .section-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | margin-bottom: 15px; |
| | | padding-bottom: 10px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | } |
| | | } |
| | | |
| | | .consumption-value { |
| | | font-weight: bold; |
| | | color: #409eff; |
| | | } |
| | | |
| | | .amount-value { |
| | | font-weight: bold; |
| | | color: #67c23a; |
| | | } |
| | | |
| | | .total-value { |
| | | font-weight: bold; |
| | | color: #e6a23c; |
| | | } |
| | | |
| | | .total-amount-value { |
| | | font-weight: bold; |
| | | color: #f56c6c; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .pagination-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- æç´¢åºå --> |
| | | <div class="search_form"> |
| | | <el-form :model="searchForm" |
| | | :inline="true"> |
| | | <el-form-item label="è½æºç±»å:"> |
| | | <el-select v-model="searchForm.energyTyep" |
| | | placeholder="å
¨é¨" |
| | | clearable |
| | | style="width: 120px;" |
| | | @change="handleQuery"> |
| | | <el-option label="æ°" |
| | | value="gas" /> |
| | | <el-option label="çµ" |
| | | value="electricity" /> |
| | | <el-option label="æ°´" |
| | | value="water" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="è½æºåç§°:"> |
| | | <el-input v-model="searchForm.energyName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery">æ¥è¯¢</el-button> |
| | | <el-button @click="handleReset">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div> |
| | | <el-button type="primary" |
| | | @click="handleAdd">æ°å¢</el-button> |
| | | <!-- <el-button type="success" |
| | | @click="handleImport">导å
¥</el-button> --> |
| | | <el-button type="warning" |
| | | @click="handleExport">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | <!-- æ°æ®è¡¨æ ¼ --> |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" |
| | | v-loading="tableLoading" |
| | | border |
| | | height="calc(100vh - 350px)" |
| | | stripe> |
| | | <el-table-column type="selection" |
| | | width="55" |
| | | align="center" /> |
| | | <el-table-column prop="energyTyep" |
| | | label="è½æºç±»å" |
| | | width="100" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getEnergyTypeType(scope.row.energyTyep)"> |
| | | {{ scope.row.energyTyep }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="energyName" |
| | | label="è½æºåç§°" |
| | | align="center" /> |
| | | <el-table-column prop="unitPrice" |
| | | label="åä»·" |
| | | sortable |
| | | align="right"> |
| | | <template #default="scope"> |
| | | <span>{{ scope.row.unitPrice }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="夿³¨" |
| | | prop="remark" |
| | | align="center" /> |
| | | <el-table-column prop="unit" |
| | | label="åä½" |
| | | align="center" /> |
| | | <el-table-column prop="createUserName" |
| | | label="å建人" |
| | | align="center" /> |
| | | <el-table-column prop="createTime" |
| | | label="å建æ¶é´" |
| | | sortable |
| | | align="center" /> |
| | | <el-table-column label="æä½" |
| | | align="center" |
| | | fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" |
| | | link |
| | | @click="handleDetail(scope.row)">详æ
</el-button> |
| | | <el-button type="danger" |
| | | link |
| | | @click="handleDelete(scope.row)">å é¤</el-button> |
| | | <el-button type="primary" |
| | | link |
| | | @click="handleEdit(scope.row)">ç¼è¾</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <!-- å页 --> |
| | | <div class="pagination-container"> |
| | | <el-pagination v-model:current-page="page.current" |
| | | v-model:page-size="page.size" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :total="page.total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" /> |
| | | </div> |
| | | </div> |
| | | <!-- æ°å¢/ç¼è¾å¼¹çª --> |
| | | <el-dialog v-model="dialogVisible" |
| | | :title="dialogTitle" |
| | | width="600px"> |
| | | <el-form :model="form" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | label-width="100px"> |
| | | <el-form-item label="è½æºåç§°" |
| | | prop="energyName"> |
| | | <el-input v-model="form.energyName" |
| | | placeholder="请è¾å
¥" /> |
| | | </el-form-item> |
| | | <el-form-item label="è½æºç±»å" |
| | | prop="energyTyep"> |
| | | <el-select v-model="form.energyTyep" |
| | | placeholder="è¯·éæ©" |
| | | style="width: 100%;"> |
| | | <el-option label="æ°" |
| | | value="æ°" /> |
| | | <el-option label="çµ" |
| | | value="çµ" /> |
| | | <el-option label="æ°´" |
| | | value="æ°´" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | type="textarea" |
| | | rows="3" /> |
| | | </el-form-item> |
| | | <el-form-item label="åä½" |
| | | prop="unit"> |
| | | <el-input v-model="form.unit" |
| | | placeholder="请è¾å
¥" /> |
| | | </el-form-item> |
| | | <el-form-item label="åä»·" |
| | | prop="unitPrice"> |
| | | <el-input-number v-model="form.unitPrice" |
| | | :precision="2" |
| | | :min="0" |
| | | style="width: 100%;" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="handleSubmit">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 详æ
å¼¹çª --> |
| | | <el-dialog v-model="detailDialogVisible" |
| | | title="è½æºç±»å详æ
" |
| | | width="600px"> |
| | | <el-form :model="detailForm" |
| | | label-width="100px" |
| | | disabled> |
| | | <el-form-item label="è½æºç±»å"> |
| | | <el-tag :type="getEnergyTypeType(detailForm.energyTyep)"> |
| | | {{ detailForm.energyTyep }} |
| | | </el-tag> |
| | | </el-form-item> |
| | | <el-form-item label="è½æºåç§°"> |
| | | <el-input v-model="detailForm.energyName" /> |
| | | </el-form-item> |
| | | <el-form-item label="åä»·"> |
| | | <el-input v-model="detailForm.unitPrice" /> |
| | | </el-form-item> |
| | | <el-form-item label="åä½"> |
| | | <el-input v-model="detailForm.unit" /> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨"> |
| | | <el-input v-model="detailForm.remark" |
| | | type="textarea" |
| | | rows="3" /> |
| | | </el-form-item> |
| | | <el-form-item label="å建人"> |
| | | <el-input v-model="detailForm.createUserName" /> |
| | | </el-form-item> |
| | | <el-form-item label="å建æ¶é´"> |
| | | <el-input v-model="detailForm.createTime" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="detailDialogVisible = false">å
³é</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { |
| | | energyTypeListPage, |
| | | energyTypeAdd, |
| | | energyTypeDelete, |
| | | } from "@/api/energyManagement/energyType"; |
| | | |
| | | import { More } from "@element-plus/icons-vue"; |
| | | |
| | | // æç´¢è¡¨å |
| | | const searchForm = reactive({ |
| | | energyTyep: "", |
| | | energyName: "", |
| | | }); |
| | | |
| | | // è¡¨æ ¼æ°æ® |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | |
| | | // å页 |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | total: 0, |
| | | }); |
| | | |
| | | // å¼¹çªæ§å¶ |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref("æ°å¢è½æºç±»å"); |
| | | const formRef = ref(null); |
| | | const isEdit = ref(false); |
| | | const currentId = ref(null); |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = reactive({ |
| | | energyName: "", |
| | | energyTyep: "", |
| | | id: "", |
| | | remark: "", |
| | | unit: "", |
| | | unitPrice: 0, |
| | | }); |
| | | const { proxy } = getCurrentInstance(); |
| | | // è¡¨åæ ¡éªè§å |
| | | const rules = { |
| | | energyTyep: [ |
| | | { required: true, message: "è¯·éæ©è½æºç±»å", trigger: "change" }, |
| | | ], |
| | | energyName: [{ required: true, message: "请è¾å
¥è½æºåç§°", trigger: "blur" }], |
| | | unitPrice: [{ required: true, message: "请è¾å
¥åä»·", trigger: "blur" }], |
| | | unit: [{ required: true, message: "请è¾å
¥åä½", trigger: "blur" }], |
| | | }; |
| | | |
| | | // 详æ
å¼¹çª |
| | | const detailDialogVisible = ref(false); |
| | | const detailForm = reactive({ |
| | | energyTyep: "", |
| | | energyName: "", |
| | | unitPrice: "", |
| | | unit: "", |
| | | remark: "", |
| | | createUserName: "", |
| | | createUserNameOrganization: "", |
| | | createTime: "", |
| | | updateTime: "", |
| | | }); |
| | | |
| | | // è·åè½æºç±»åæ ·å¼ |
| | | const getEnergyTypeType = type => { |
| | | const typeMap = { |
| | | æ°: "success", |
| | | çµ: "warning", |
| | | æ°´: "primary", |
| | | }; |
| | | return typeMap[type] || "info"; |
| | | }; |
| | | |
| | | // çææ¨¡ææ°æ® |
| | | const generateMockData = () => { |
| | | const data = [ |
| | | { |
| | | id: 1, |
| | | energyTyep: "æ°", |
| | | energyName: "è¸æ±½", |
| | | unitPrice: "0.00", |
| | | unit: "T", |
| | | createUserName: "ç½æ´å·²ç´ç»", |
| | | createUserNameOrganization: "å®å¤ä¸é¶ç»ä¸å®ä¸é墿éå
¬å¸", |
| | | createTime: "2022-11-09 14:14:05", |
| | | updateTime: "2022-11-10 18:14:48", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 2, |
| | | energyTyep: "çµ", |
| | | energyName: "çµé", |
| | | unitPrice: "0.00", |
| | | unit: "度", |
| | | createUserName: "ççªå·²ç´ç»", |
| | | createUserNameOrganization: "å®å¤ä¸é¶ç»ä¸å®ä¸é墿éå
¬å¸", |
| | | createTime: "2022-10-08 17:27:27", |
| | | updateTime: "2022-11-10 18:14:40", |
| | | remark: "", |
| | | }, |
| | | { |
| | | id: 3, |
| | | energyTyep: "æ°´", |
| | | energyName: "䏿°´", |
| | | unitPrice: "0.00", |
| | | unit: "m³", |
| | | createUserName: "ççªå·²ç´ç»", |
| | | createUserNameOrganization: "å®å¤ä¸é¶ç»ä¸å®ä¸é墿éå
¬å¸", |
| | | createTime: "2022-10-08 10:03:03", |
| | | updateTime: "2022-11-10 18:10:31", |
| | | remark: "", |
| | | }, |
| | | ]; |
| | | return data; |
| | | }; |
| | | |
| | | // æ¥è¯¢ |
| | | const handleQuery = () => { |
| | | tableLoading.value = true; |
| | | let params = { |
| | | current: page.current, |
| | | size: page.size, |
| | | energyTyep: searchForm.energyTyep, |
| | | energyName: searchForm.energyName, |
| | | }; |
| | | energyTypeListPage(params) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | tableLoading.value = false; |
| | | } else { |
| | | ElMessage.error(res.message || "æ¥è¯¢å¤±è´¥"); |
| | | tableLoading.value = false; |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | ElMessage.error("ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | // éç½® |
| | | const handleReset = () => { |
| | | searchForm.energyTyep = ""; |
| | | searchForm.energyName = ""; |
| | | page.current = 1; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // æ°å¢ |
| | | const handleAdd = () => { |
| | | isEdit.value = false; |
| | | currentId.value = null; |
| | | dialogTitle.value = "æ°å¢è½æºç±»å"; |
| | | resetForm(); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | // ç¼è¾ |
| | | const handleEdit = row => { |
| | | isEdit.value = true; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = "ç¼è¾è½æºç±»å"; |
| | | Object.assign(form, row); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | // 详æ
|
| | | const handleDetail = row => { |
| | | Object.assign(detailForm, row); |
| | | detailDialogVisible.value = true; |
| | | }; |
| | | |
| | | // å é¤ |
| | | const handleDelete = row => { |
| | | ElMessageBox.confirm("ç¡®å®è¦å é¤è¯¥è½æºç±»ååï¼", "æç¤º", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(() => { |
| | | tableLoading.value = true; |
| | | energyTypeDelete([row.id]) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | ElMessage.success("å 餿å"); |
| | | handleQuery(); |
| | | } else { |
| | | ElMessage.error(res.message || "å é¤å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | ElMessage.error("ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | // å¤å¶ |
| | | const handleCopy = row => { |
| | | isEdit.value = false; |
| | | currentId.value = null; |
| | | dialogTitle.value = "å¤å¶è½æºç±»å"; |
| | | Object.assign(form, row); |
| | | delete form.id; |
| | | dialogVisible.value = true; |
| | | ElMessage.success("å·²å¤å¶å°è¡¨å"); |
| | | }; |
| | | |
| | | // é置表å |
| | | const resetForm = () => { |
| | | form.energyName = ""; |
| | | form.energyTyep = ""; |
| | | form.id = ""; |
| | | form.remark = ""; |
| | | form.unit = ""; |
| | | form.unitPrice = 0; |
| | | }; |
| | | |
| | | // æäº¤è¡¨å |
| | | const handleSubmit = () => { |
| | | formRef.value.validate(valid => { |
| | | if (valid) { |
| | | tableLoading.value = true; |
| | | energyTypeAdd(form) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | ElMessage.success(isEdit.value ? "ç¼è¾æå" : "æ°å¢æå"); |
| | | dialogVisible.value = false; |
| | | handleQuery(); |
| | | } else { |
| | | ElMessage.error(res.message || "æä½å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | ElMessage.error("ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 导å
¥ |
| | | const handleImport = () => { |
| | | ElMessage.success("导å
¥æå"); |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleExport = () => { |
| | | // proxy.download("/energy/export", { ...searchForm.value }, "è½èç±»å.xlsx"); |
| | | proxy.download("/energy/export", {}, "è½èç±»å.xlsx"); |
| | | }; |
| | | |
| | | // å页大å°åå |
| | | const handleSizeChange = val => { |
| | | page.size = val; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // 页ç åå |
| | | const handleCurrentChange = val => { |
| | | page.current = val; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | handleQuery(); |
| | | }); |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | .app-container { |
| | | padding: 24px; |
| | | background-color: #f0f2f5; |
| | | min-height: calc(100vh - 48px); |
| | | } |
| | | |
| | | .search_form { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 24px; |
| | | padding: 20px; |
| | | background-color: #ffffff; |
| | | border-radius: 6px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08); |
| | | } |
| | | } |
| | | |
| | | .table_list { |
| | | // margin-bottom: 24px; |
| | | background-color: #ffffff; |
| | | border-radius: 6px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); |
| | | overflow: hidden; |
| | | height: calc(100vh - 250px); |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | border: none; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | |
| | | .el-table__header-wrapper { |
| | | background-color: #fafafa; |
| | | |
| | | th { |
| | | background-color: #fafafa; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 14px 0; |
| | | } |
| | | } |
| | | |
| | | .el-table__body-wrapper { |
| | | tr { |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | td { |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 12px 0; |
| | | } |
| | | } |
| | | |
| | | tr.current-row { |
| | | background-color: #ecf5ff; |
| | | } |
| | | } |
| | | |
| | | .el-table__empty-block { |
| | | padding: 40px 0; |
| | | } |
| | | } |
| | | |
| | | .pagination-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | padding: 16px 20px; |
| | | background-color: #ffffff; |
| | | border-top: 1px solid #ebeef5; |
| | | border-radius: 0 0 12px 12px; |
| | | } |
| | | |
| | | :deep(.el-button) { |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | transform: translateY(-1px); |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog) { |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | |
| | | .el-dialog__header { |
| | | background-color: #fafafa; |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 20px 24px; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | .el-dialog__body { |
| | | padding: 24px; |
| | | } |
| | | |
| | | .el-dialog__footer { |
| | | padding: 16px 24px; |
| | | border-top: 1px solid #ebeef5; |
| | | background-color: #fafafa; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-form) { |
| | | .el-form-item { |
| | | margin-bottom: 20px; |
| | | |
| | | .el-form-item__label { |
| | | font-weight: 500; |
| | | color: #303133; |
| | | } |
| | | |
| | | .el-input, |
| | | .el-select, |
| | | .el-date-picker, |
| | | .el-input-number { |
| | | width: 100%; |
| | | |
| | | // .el-input__inner { |
| | | // border-radius: 6px; |
| | | // border: 1px solid #dcdfe6; |
| | | // transition: all 0.3s ease; |
| | | |
| | | // &:focus { |
| | | // border-color: #409eff; |
| | | // box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2); |
| | | // } |
| | | // } |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep(.el-tag) { |
| | | border-radius: 4px; |
| | | padding: 2px 8px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .app-container { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .search_form { |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | gap: 12px; |
| | | |
| | | .el-form { |
| | | width: 100%; |
| | | |
| | | .el-form-item { |
| | | width: 100%; |
| | | } |
| | | } |
| | | |
| | | > div { |
| | | width: 100%; |
| | | display: flex; |
| | | gap: 12px; |
| | | |
| | | .el-button { |
| | | flex: 1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | th, |
| | | td { |
| | | padding: 10px 0; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog) { |
| | | width: 90% !important; |
| | | margin: 20px auto !important; |
| | | } |
| | | } |
| | | .consumption-value { |
| | | font-weight: bold; |
| | | color: #409eff; |
| | | } |
| | | |
| | | .consumption-unit { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | margin-left: 4px; |
| | | } |
| | | .search_form { |
| | | :deep(.el-form-item) { |
| | | margin-bottom: 0px !important; |
| | | } |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- æç´¢åºå --> |
| | | <div class="search_form"> |
| | | <el-form :model="searchForm" |
| | | :inline="true"> |
| | | <el-form-item label="è½èç±»å:"> |
| | | <el-select v-model="searchForm.energyType" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 140px;" |
| | | @change="handleQuery"> |
| | | <el-option label="æ°´" |
| | | value="water" /> |
| | | <el-option label="çµ" |
| | | value="electricity" /> |
| | | <el-option label="æ°" |
| | | value="gas" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <!-- <el-form-item label="æ¥æèå´:"> |
| | | <el-date-picker v-model="searchForm.dateRange" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 240px;" |
| | | @change="handleQuery" /> |
| | | </el-form-item> --> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery">æç´¢</el-button> |
| | | <el-button @click="handleReset">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div> |
| | | <!-- <el-button type="primary" |
| | | @click="handleAdd">æ°å¢</el-button> --> |
| | | <el-button type="success" |
| | | @click="handleExport">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | <!-- æ°æ®è¡¨æ ¼ --> |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" |
| | | v-loading="tableLoading" |
| | | border |
| | | height="calc(100vh - 350px)" |
| | | stripe> |
| | | <el-table-column type="index" |
| | | label="åºå·" |
| | | width="60" |
| | | align="center" /> |
| | | <el-table-column prop="meterReadingDate" |
| | | label="æè¡¨æ¥æ" |
| | | width="120" |
| | | sortable |
| | | align="center" /> |
| | | <el-table-column prop="energyType" |
| | | label="è½æºç±»å" |
| | | width="100" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getEnergyTypeType(scope.row.energyTyep)"> |
| | | {{ scope.row.energyTyep }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="energyName" |
| | | label="è½æºåç§°" |
| | | align="center" /> |
| | | <el-table-column prop="meterReadingLocation" |
| | | label="æè¡¨ä½ç½®" |
| | | align="center" /> |
| | | <el-table-column prop="startCode" |
| | | label="èµ·ç " |
| | | sortable |
| | | align="right" /> |
| | | <el-table-column prop="stopCode" |
| | | label="æ¢ç " |
| | | sortable |
| | | align="right" /> |
| | | <el-table-column prop="dosage" |
| | | label="ç¨é" |
| | | sortable |
| | | align="right"> |
| | | <template #default="scope"> |
| | | <span class="consumption-value">{{ scope.row.dosage }}</span> |
| | | <span class="consumption-unit">{{ scope.row.unit }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <!-- <el-table-column prop="unit" |
| | | label="åä½" |
| | | width="80" |
| | | align="center" /> --> |
| | | <!-- <el-table-column prop="energyId" |
| | | label="è½æºç±»åID" |
| | | width="120" |
| | | align="center" /> --> |
| | | <el-table-column prop="remark" |
| | | label="夿³¨" |
| | | min-width="150" |
| | | show-overflow-tooltip /> |
| | | <!-- <el-table-column label="æä½" |
| | | width="180" |
| | | align="center" |
| | | fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" |
| | | link |
| | | @click="handleEdit(scope.row)">ç¼è¾</el-button> |
| | | <el-button type="danger" |
| | | link |
| | | @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> --> |
| | | </el-table> |
| | | <div class="pagination-container"> |
| | | <el-pagination v-model:current-page="page.current" |
| | | v-model:page-size="page.size" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :total="page.total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" /> |
| | | </div> |
| | | </div> |
| | | <!-- å页 --> |
| | | <!-- æ°å¢/ç¼è¾å¼¹çª --> |
| | | <el-dialog v-model="dialogVisible" |
| | | :title="dialogTitle" |
| | | width="600px"> |
| | | <el-form :model="form" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | label-width="120px"> |
| | | <el-form-item label="æè¡¨æ¥æ" |
| | | prop="meterReadingDate"> |
| | | <el-date-picker v-model="form.meterReadingDate" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 100%;" /> |
| | | </el-form-item> |
| | | <el-form-item label="è½æºç±»å" |
| | | prop="energyType"> |
| | | <el-select v-model="form.energyType" |
| | | placeholder="è¯·éæ©" |
| | | style="width: 100%;" |
| | | @change="handleEnergyTypeChange"> |
| | | <el-option v-for="item in energyTypeList" |
| | | :key="item.id" |
| | | :label="item.energyName" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æè¡¨ä½ç½®" |
| | | prop="meterReadingLocation"> |
| | | <el-input v-model="form.meterReadingLocation" |
| | | placeholder="请è¾å
¥" /> |
| | | </el-form-item> |
| | | <el-form-item label="èµ·ç " |
| | | prop="startCode"> |
| | | <el-input-number v-model="form.startCode" |
| | | :min="0" |
| | | style="width: 100%;" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¢ç " |
| | | prop="stopCode"> |
| | | <el-input-number v-model="form.stopCode" |
| | | :min="0" |
| | | style="width: 100%;" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¨é" |
| | | prop="dosage"> |
| | | <el-input-number v-model="form.dosage" |
| | | :min="0" |
| | | style="width: 100%;" /> |
| | | </el-form-item> |
| | | <el-form-item label="åä½" |
| | | prop="unit"> |
| | | <el-input v-model="form.unit" |
| | | disabled |
| | | placeholder="请è¾å
¥" /> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | type="textarea" |
| | | rows="3" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" |
| | | @click="handleSubmit">ç¡®å®</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { Watermelon, Lightning } from "@element-plus/icons-vue"; |
| | | import { |
| | | energyConsumptionDetailListPage, |
| | | energyConsumptionDetailAdd, |
| | | energyConsumptionDetailDelete, |
| | | energyTypeListPage, |
| | | } from "@/api/energyManagement/energyType"; |
| | | |
| | | // æç´¢è¡¨å |
| | | const searchForm = reactive({ |
| | | energyType: "", |
| | | dateRange: [], |
| | | }); |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | // ç»è®¡æ°æ® |
| | | const statistics = reactive({ |
| | | waterTotal: 1256.8, |
| | | waterAmount: "3,142.00", |
| | | electricityTotal: 8520.5, |
| | | electricityAmount: "6,816.40", |
| | | gasTotal: 3200.6, |
| | | gasAmount: "9,601.80", |
| | | }); |
| | | |
| | | // è¡¨æ ¼æ°æ® |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | |
| | | // å页 |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | total: 0, |
| | | }); |
| | | |
| | | // å¼¹çªæ§å¶ |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref("æ°å¢è½èè®°å½"); |
| | | const formRef = ref(null); |
| | | const isEdit = ref(false); |
| | | const currentId = ref(null); |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = reactive({ |
| | | meterReadingDate: "", |
| | | energyType: "", |
| | | energyName: "", |
| | | energyId: "", |
| | | meterReadingLocation: "", |
| | | startCode: 0, |
| | | stopCode: 0, |
| | | dosage: 0, |
| | | unit: "", |
| | | remark: "", |
| | | type: "åå
¬", |
| | | }); |
| | | |
| | | // è¡¨åæ ¡éªè§å |
| | | const rules = { |
| | | meterReadingDate: [ |
| | | { required: true, message: "è¯·éæ©æè¡¨æ¥æ", trigger: "change" }, |
| | | ], |
| | | energyType: [ |
| | | { required: true, message: "è¯·éæ©è½æºç±»å", trigger: "change" }, |
| | | ], |
| | | energyName: [ |
| | | { required: true, message: "è¯·éæ©è½æºåç§°", trigger: "change" }, |
| | | ], |
| | | energyId: [{ required: true, message: "è¯·éæ©è½æºç±»å", trigger: "change" }], |
| | | meterReadingLocation: [ |
| | | { required: true, message: "请è¾å
¥æè¡¨ä½ç½®", trigger: "blur" }, |
| | | ], |
| | | startCode: [{ required: true, message: "请è¾å
¥èµ·ç ", trigger: "blur" }], |
| | | stopCode: [{ required: true, message: "请è¾å
¥æ¢ç ", trigger: "blur" }], |
| | | dosage: [{ required: true, message: "请è¾å
¥ç¨é", trigger: "blur" }], |
| | | unit: [{ required: true, message: "请è¾å
¥åä½", trigger: "blur" }], |
| | | }; |
| | | |
| | | // è·åè½èç±»åæ ·å¼ |
| | | const getEnergyTypeType = type => { |
| | | const typeMap = { |
| | | æ°´: "primary", |
| | | çµ: "warning", |
| | | æ°: "success", |
| | | water: "primary", |
| | | electricity: "warning", |
| | | gas: "success", |
| | | }; |
| | | return typeMap[type] || "info"; |
| | | }; |
| | | |
| | | // è·åè½èç±»åææ¬ |
| | | const getEnergyTypeText = type => { |
| | | const textMap = { |
| | | water: "æ°´", |
| | | electricity: "çµ", |
| | | gas: "æ°", |
| | | }; |
| | | return textMap[type] || type; |
| | | }; |
| | | |
| | | // æ¥è¯¢ |
| | | const handleQuery = () => { |
| | | tableLoading.value = true; |
| | | const params = { |
| | | current: page.current, |
| | | size: page.size, |
| | | type: "åå
¬", |
| | | // energyType: searchForm.energyType, |
| | | // startDate: |
| | | // searchForm.dateRange && searchForm.dateRange.length === 2 |
| | | // ? searchForm.dateRange[0] |
| | | // : null, |
| | | // endDate: |
| | | // searchForm.dateRange && searchForm.dateRange.length === 2 |
| | | // ? searchForm.dateRange[1] |
| | | // : null, |
| | | }; |
| | | energyConsumptionDetailListPage(params) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | } else { |
| | | ElMessage.error(res.message || "æ¥è¯¢å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | ElMessage.error("ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | const energyTypeList = ref([]); |
| | | const getEnergyTypeList = () => { |
| | | energyTypeListPage({ current: -1, size: -1 }) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | energyTypeList.value = res.data.records; |
| | | } else { |
| | | ElMessage.error(res.message || "æ¥è¯¢å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | ElMessage.error("ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | }); |
| | | }; |
| | | |
| | | // éç½® |
| | | const handleReset = () => { |
| | | searchForm.energyType = ""; |
| | | searchForm.dateRange = []; |
| | | page.current = 1; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleExport = () => { |
| | | proxy.download( |
| | | "/energyConsumptionDetail/export", |
| | | { type: "åå
¬" }, |
| | | "è½èæç».xlsx" |
| | | ); |
| | | }; |
| | | |
| | | // å页大å°åå |
| | | const handleSizeChange = val => { |
| | | page.size = val; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // 页ç åå |
| | | const handleCurrentChange = val => { |
| | | page.current = val; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // å¤çè½æºç±»ååå |
| | | const handleEnergyTypeChange = value => { |
| | | const selectedType = energyTypeList.value.find(item => item.id === value); |
| | | if (selectedType) { |
| | | form.energyName = selectedType.energyName; |
| | | form.energyId = selectedType.id; |
| | | form.unit = selectedType.unit; |
| | | } |
| | | }; |
| | | |
| | | // æ°å¢ |
| | | const handleAdd = () => { |
| | | isEdit.value = false; |
| | | currentId.value = null; |
| | | dialogTitle.value = "æ°å¢è½èè®°å½"; |
| | | resetForm(); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | // ç¼è¾ |
| | | const handleEdit = row => { |
| | | isEdit.value = true; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = "ç¼è¾è½èè®°å½"; |
| | | Object.assign(form, row); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | // å é¤ |
| | | const handleDelete = row => { |
| | | ElMessageBox.confirm("ç¡®å®è¦å é¤è¯¥è½èè®°å½åï¼", "æç¤º", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(() => { |
| | | tableLoading.value = true; |
| | | energyConsumptionDetailDelete([row.id]) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | ElMessage.success("å 餿å"); |
| | | handleQuery(); |
| | | } else { |
| | | ElMessage.error(res.message || "å é¤å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | ElMessage.error("ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | // é置表å |
| | | const resetForm = () => { |
| | | form.meterReadingDate = ""; |
| | | form.energyType = ""; |
| | | form.energyName = ""; |
| | | form.energyId = ""; |
| | | form.meterReadingLocation = ""; |
| | | form.startCode = 0; |
| | | form.stopCode = 0; |
| | | form.dosage = 0; |
| | | form.unit = ""; |
| | | form.remark = ""; |
| | | form.type = "åå
¬"; |
| | | }; |
| | | |
| | | // æäº¤è¡¨å |
| | | const handleSubmit = () => { |
| | | formRef.value.validate(valid => { |
| | | if (valid) { |
| | | tableLoading.value = true; |
| | | energyConsumptionDetailAdd(form) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | ElMessage.success(isEdit.value ? "ç¼è¾æå" : "æ°å¢æå"); |
| | | dialogVisible.value = false; |
| | | handleQuery(); |
| | | } else { |
| | | ElMessage.error(res.message || "æä½å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | ElMessage.error("ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getEnergyTypeList(); |
| | | handleQuery(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .app-container { |
| | | padding: 24px; |
| | | background-color: #f0f2f5; |
| | | min-height: calc(100vh - 48px); |
| | | } |
| | | |
| | | .search_form { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 24px; |
| | | padding: 20px; |
| | | background-color: #ffffff; |
| | | border-radius: 6px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08); |
| | | } |
| | | } |
| | | |
| | | .table_list { |
| | | // margin-bottom: 24px; |
| | | background-color: #ffffff; |
| | | border-radius: 6px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); |
| | | overflow: hidden; |
| | | height: calc(100vh - 250px); |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | border: none; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | |
| | | .el-table__header-wrapper { |
| | | background-color: #fafafa; |
| | | |
| | | th { |
| | | background-color: #fafafa; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 14px 0; |
| | | } |
| | | } |
| | | |
| | | .el-table__body-wrapper { |
| | | tr { |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | td { |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 12px 0; |
| | | } |
| | | } |
| | | |
| | | tr.current-row { |
| | | background-color: #ecf5ff; |
| | | } |
| | | } |
| | | |
| | | .el-table__empty-block { |
| | | padding: 40px 0; |
| | | } |
| | | } |
| | | |
| | | .pagination-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | padding: 16px 20px; |
| | | background-color: #ffffff; |
| | | border-top: 1px solid #ebeef5; |
| | | border-radius: 0 0 12px 12px; |
| | | } |
| | | |
| | | :deep(.el-button) { |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | transform: translateY(-1px); |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog) { |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | |
| | | .el-dialog__header { |
| | | background-color: #fafafa; |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 20px 24px; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | .el-dialog__body { |
| | | padding: 24px; |
| | | } |
| | | |
| | | .el-dialog__footer { |
| | | padding: 16px 24px; |
| | | border-top: 1px solid #ebeef5; |
| | | background-color: #fafafa; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-form) { |
| | | .el-form-item { |
| | | margin-bottom: 20px; |
| | | |
| | | .el-form-item__label { |
| | | font-weight: 500; |
| | | color: #303133; |
| | | } |
| | | |
| | | .el-input, |
| | | .el-select, |
| | | .el-date-picker, |
| | | .el-input-number { |
| | | width: 100%; |
| | | |
| | | // .el-input__inner { |
| | | // border-radius: 6px; |
| | | // border: 1px solid #dcdfe6; |
| | | // transition: all 0.3s ease; |
| | | |
| | | // &:focus { |
| | | // border-color: #409eff; |
| | | // box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2); |
| | | // } |
| | | // } |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep(.el-tag) { |
| | | border-radius: 4px; |
| | | padding: 2px 8px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .app-container { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .search_form { |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | gap: 12px; |
| | | |
| | | .el-form { |
| | | width: 100%; |
| | | |
| | | .el-form-item { |
| | | width: 100%; |
| | | } |
| | | } |
| | | |
| | | > div { |
| | | width: 100%; |
| | | display: flex; |
| | | gap: 12px; |
| | | |
| | | .el-button { |
| | | flex: 1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | th, |
| | | td { |
| | | padding: 10px 0; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog) { |
| | | width: 90% !important; |
| | | margin: 20px auto !important; |
| | | } |
| | | } |
| | | .consumption-value { |
| | | font-weight: bold; |
| | | color: #409eff; |
| | | } |
| | | |
| | | .consumption-unit { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | margin-left: 4px; |
| | | } |
| | | .search_form { |
| | | :deep(.el-form-item) { |
| | | margin-bottom: 0px !important; |
| | | } |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- æç´¢åºå --> |
| | | <div class="search_form"> |
| | | <el-form :model="searchForm" |
| | | :inline="true"> |
| | | <el-form-item label="è½èç±»å:"> |
| | | <el-select v-model="searchForm.energyType" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 140px;" |
| | | @change="handleQuery"> |
| | | <el-option label="æ°´" |
| | | value="water" /> |
| | | <el-option label="çµ" |
| | | value="electricity" /> |
| | | <el-option label="æ°" |
| | | value="gas" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <!-- <el-form-item label="æ¥æèå´:"> |
| | | <el-date-picker v-model="searchForm.dateRange" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 240px;" |
| | | @change="handleQuery" /> |
| | | </el-form-item> --> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery">æç´¢</el-button> |
| | | <el-button @click="handleReset">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div> |
| | | <el-button type="primary" |
| | | @click="handleAdd">æ°å¢</el-button> |
| | | <el-button type="success" |
| | | @click="handleExport">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | <!-- æ°æ®è¡¨æ ¼ --> |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" |
| | | v-loading="tableLoading" |
| | | border |
| | | height="calc(100vh - 350px)" |
| | | stripe> |
| | | <el-table-column type="index" |
| | | label="åºå·" |
| | | width="60" |
| | | align="center" /> |
| | | <el-table-column prop="meterReadingDate" |
| | | label="æè¡¨æ¥æ" |
| | | width="120" |
| | | sortable |
| | | align="center" /> |
| | | <el-table-column prop="energyType" |
| | | label="è½æºç±»å" |
| | | width="100" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getEnergyTypeType(scope.row.energyTyep)"> |
| | | {{ scope.row.energyTyep }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="energyName" |
| | | label="è½æºåç§°" |
| | | align="center" /> |
| | | <el-table-column prop="meterReadingLocation" |
| | | label="æè¡¨ä½ç½®" |
| | | align="center" /> |
| | | <el-table-column prop="startCode" |
| | | label="èµ·ç " |
| | | sortable |
| | | align="right" /> |
| | | <el-table-column prop="stopCode" |
| | | label="æ¢ç " |
| | | sortable |
| | | align="right" /> |
| | | <el-table-column prop="dosage" |
| | | label="ç¨é" |
| | | sortable |
| | | align="right"> |
| | | <template #default="scope"> |
| | | <span class="consumption-value">{{ scope.row.dosage }}</span> |
| | | <span class="consumption-unit">{{ scope.row.unit }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <!-- <el-table-column prop="unit" |
| | | label="åä½" |
| | | width="80" |
| | | align="center" /> --> |
| | | <!-- <el-table-column prop="energyId" |
| | | label="è½æºç±»åID" |
| | | width="120" |
| | | align="center" /> --> |
| | | <el-table-column prop="remark" |
| | | label="夿³¨" |
| | | min-width="150" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æä½" |
| | | width="180" |
| | | align="center" |
| | | fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" |
| | | link |
| | | @click="handleEdit(scope.row)">ç¼è¾</el-button> |
| | | <el-button type="danger" |
| | | link |
| | | @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div class="pagination-container"> |
| | | <el-pagination v-model:current-page="page.current" |
| | | v-model:page-size="page.size" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :total="page.total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" /> |
| | | </div> |
| | | </div> |
| | | <!-- å页 --> |
| | | <!-- æ°å¢/ç¼è¾å¼¹çª --> |
| | | <el-dialog v-model="dialogVisible" |
| | | :title="dialogTitle" |
| | | width="600px"> |
| | | <el-form :model="form" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | label-width="120px"> |
| | | <el-form-item label="æè¡¨æ¥æ" |
| | | prop="meterReadingDate"> |
| | | <el-date-picker v-model="form.meterReadingDate" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 100%;" /> |
| | | </el-form-item> |
| | | <el-form-item label="è½æºç±»å" |
| | | prop="energyType"> |
| | | <el-select v-model="form.energyType" |
| | | placeholder="è¯·éæ©" |
| | | style="width: 100%;" |
| | | @change="handleEnergyTypeChange"> |
| | | <el-option v-for="item in energyTypeList" |
| | | :key="item.id" |
| | | :label="item.energyName" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æè¡¨ä½ç½®" |
| | | prop="meterReadingLocation"> |
| | | <el-input v-model="form.meterReadingLocation" |
| | | placeholder="请è¾å
¥" /> |
| | | </el-form-item> |
| | | <el-form-item label="èµ·ç " |
| | | prop="startCode"> |
| | | <el-input-number v-model="form.startCode" |
| | | :min="0" |
| | | style="width: 100%;" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¢ç " |
| | | prop="stopCode"> |
| | | <el-input-number v-model="form.stopCode" |
| | | :min="0" |
| | | style="width: 100%;" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¨é" |
| | | prop="dosage"> |
| | | <el-input-number v-model="form.dosage" |
| | | :min="0" |
| | | style="width: 100%;" /> |
| | | </el-form-item> |
| | | <el-form-item label="åä½" |
| | | prop="unit"> |
| | | <el-input v-model="form.unit" |
| | | disabled |
| | | placeholder="请è¾å
¥" /> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | type="textarea" |
| | | rows="3" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" |
| | | @click="handleSubmit">ç¡®å®</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { Watermelon, Lightning } from "@element-plus/icons-vue"; |
| | | import { |
| | | energyConsumptionDetailListPage, |
| | | energyConsumptionDetailAdd, |
| | | energyConsumptionDetailDelete, |
| | | energyTypeListPage, |
| | | } from "@/api/energyManagement/energyType"; |
| | | |
| | | // æç´¢è¡¨å |
| | | const searchForm = reactive({ |
| | | energyType: "", |
| | | dateRange: [], |
| | | }); |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | // ç»è®¡æ°æ® |
| | | const statistics = reactive({ |
| | | waterTotal: 1256.8, |
| | | waterAmount: "3,142.00", |
| | | electricityTotal: 8520.5, |
| | | electricityAmount: "6,816.40", |
| | | gasTotal: 3200.6, |
| | | gasAmount: "9,601.80", |
| | | }); |
| | | |
| | | // è¡¨æ ¼æ°æ® |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | |
| | | // å页 |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | total: 0, |
| | | }); |
| | | |
| | | // å¼¹çªæ§å¶ |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref("æ°å¢è½èè®°å½"); |
| | | const formRef = ref(null); |
| | | const isEdit = ref(false); |
| | | const currentId = ref(null); |
| | | |
| | | // è¡¨åæ°æ® |
| | | const form = reactive({ |
| | | meterReadingDate: "", |
| | | energyType: "", |
| | | energyName: "", |
| | | energyId: "", |
| | | meterReadingLocation: "", |
| | | startCode: 0, |
| | | stopCode: 0, |
| | | dosage: 0, |
| | | unit: "", |
| | | remark: "", |
| | | type: "ç产", |
| | | }); |
| | | |
| | | // è¡¨åæ ¡éªè§å |
| | | const rules = { |
| | | meterReadingDate: [ |
| | | { required: true, message: "è¯·éæ©æè¡¨æ¥æ", trigger: "change" }, |
| | | ], |
| | | energyType: [ |
| | | { required: true, message: "è¯·éæ©è½æºç±»å", trigger: "change" }, |
| | | ], |
| | | energyName: [ |
| | | { required: true, message: "è¯·éæ©è½æºåç§°", trigger: "change" }, |
| | | ], |
| | | energyId: [{ required: true, message: "è¯·éæ©è½æºç±»å", trigger: "change" }], |
| | | meterReadingLocation: [ |
| | | { required: true, message: "请è¾å
¥æè¡¨ä½ç½®", trigger: "blur" }, |
| | | ], |
| | | startCode: [{ required: true, message: "请è¾å
¥èµ·ç ", trigger: "blur" }], |
| | | stopCode: [{ required: true, message: "请è¾å
¥æ¢ç ", trigger: "blur" }], |
| | | dosage: [{ required: true, message: "请è¾å
¥ç¨é", trigger: "blur" }], |
| | | unit: [{ required: true, message: "请è¾å
¥åä½", trigger: "blur" }], |
| | | }; |
| | | |
| | | // è·åè½èç±»åæ ·å¼ |
| | | const getEnergyTypeType = type => { |
| | | const typeMap = { |
| | | æ°´: "primary", |
| | | çµ: "warning", |
| | | æ°: "success", |
| | | water: "primary", |
| | | electricity: "warning", |
| | | gas: "success", |
| | | }; |
| | | return typeMap[type] || "info"; |
| | | }; |
| | | |
| | | // è·åè½èç±»åææ¬ |
| | | const getEnergyTypeText = type => { |
| | | const textMap = { |
| | | water: "æ°´", |
| | | electricity: "çµ", |
| | | gas: "æ°", |
| | | }; |
| | | return textMap[type] || type; |
| | | }; |
| | | |
| | | // æ¥è¯¢ |
| | | const handleQuery = () => { |
| | | tableLoading.value = true; |
| | | const params = { |
| | | current: page.current, |
| | | size: page.size, |
| | | type: "ç产", |
| | | // energyType: searchForm.energyType, |
| | | // startDate: |
| | | // searchForm.dateRange && searchForm.dateRange.length === 2 |
| | | // ? searchForm.dateRange[0] |
| | | // : null, |
| | | // endDate: |
| | | // searchForm.dateRange && searchForm.dateRange.length === 2 |
| | | // ? searchForm.dateRange[1] |
| | | // : null, |
| | | }; |
| | | energyConsumptionDetailListPage(params) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | } else { |
| | | ElMessage.error(res.message || "æ¥è¯¢å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | ElMessage.error("ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | const energyTypeList = ref([]); |
| | | const getEnergyTypeList = () => { |
| | | energyTypeListPage({ current: -1, size: -1 }) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | energyTypeList.value = res.data.records; |
| | | } else { |
| | | ElMessage.error(res.message || "æ¥è¯¢å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | ElMessage.error("ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | }); |
| | | }; |
| | | |
| | | // éç½® |
| | | const handleReset = () => { |
| | | searchForm.energyType = ""; |
| | | searchForm.dateRange = []; |
| | | page.current = 1; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleExport = () => { |
| | | proxy.download( |
| | | "/energyConsumptionDetail/export", |
| | | { type: "ç产" }, |
| | | "è½èæç».xlsx" |
| | | ); |
| | | }; |
| | | |
| | | // å页大å°åå |
| | | const handleSizeChange = val => { |
| | | page.size = val; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // 页ç åå |
| | | const handleCurrentChange = val => { |
| | | page.current = val; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // å¤çè½æºç±»ååå |
| | | const handleEnergyTypeChange = value => { |
| | | const selectedType = energyTypeList.value.find(item => item.id === value); |
| | | if (selectedType) { |
| | | form.energyName = selectedType.energyName; |
| | | form.energyId = selectedType.id; |
| | | form.unit = selectedType.unit; |
| | | } |
| | | }; |
| | | |
| | | // æ°å¢ |
| | | const handleAdd = () => { |
| | | isEdit.value = false; |
| | | currentId.value = null; |
| | | dialogTitle.value = "æ°å¢è½èè®°å½"; |
| | | resetForm(); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | // ç¼è¾ |
| | | const handleEdit = row => { |
| | | isEdit.value = true; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = "ç¼è¾è½èè®°å½"; |
| | | Object.assign(form, row); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | // å é¤ |
| | | const handleDelete = row => { |
| | | ElMessageBox.confirm("ç¡®å®è¦å é¤è¯¥è½èè®°å½åï¼", "æç¤º", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(() => { |
| | | tableLoading.value = true; |
| | | energyConsumptionDetailDelete([row.id]) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | ElMessage.success("å 餿å"); |
| | | handleQuery(); |
| | | } else { |
| | | ElMessage.error(res.message || "å é¤å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | ElMessage.error("ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | // é置表å |
| | | const resetForm = () => { |
| | | form.meterReadingDate = ""; |
| | | form.energyType = ""; |
| | | form.energyName = ""; |
| | | form.energyId = ""; |
| | | form.meterReadingLocation = ""; |
| | | form.startCode = 0; |
| | | form.stopCode = 0; |
| | | form.dosage = 0; |
| | | form.unit = ""; |
| | | form.remark = ""; |
| | | form.type = "ç产"; |
| | | }; |
| | | |
| | | // æäº¤è¡¨å |
| | | const handleSubmit = () => { |
| | | formRef.value.validate(valid => { |
| | | if (valid) { |
| | | tableLoading.value = true; |
| | | energyConsumptionDetailAdd(form) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | ElMessage.success(isEdit.value ? "ç¼è¾æå" : "æ°å¢æå"); |
| | | dialogVisible.value = false; |
| | | handleQuery(); |
| | | } else { |
| | | ElMessage.error(res.message || "æä½å¤±è´¥"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | ElMessage.error("ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getEnergyTypeList(); |
| | | handleQuery(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .app-container { |
| | | padding: 24px; |
| | | background-color: #f0f2f5; |
| | | min-height: calc(100vh - 48px); |
| | | } |
| | | |
| | | .search_form { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 24px; |
| | | padding: 20px; |
| | | background-color: #ffffff; |
| | | border-radius: 6px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08); |
| | | } |
| | | } |
| | | |
| | | .table_list { |
| | | // margin-bottom: 24px; |
| | | background-color: #ffffff; |
| | | border-radius: 6px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); |
| | | overflow: hidden; |
| | | height: calc(100vh - 250px); |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | border: none; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | |
| | | .el-table__header-wrapper { |
| | | background-color: #fafafa; |
| | | |
| | | th { |
| | | background-color: #fafafa; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 14px 0; |
| | | } |
| | | } |
| | | |
| | | .el-table__body-wrapper { |
| | | tr { |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | td { |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 12px 0; |
| | | } |
| | | } |
| | | |
| | | tr.current-row { |
| | | background-color: #ecf5ff; |
| | | } |
| | | } |
| | | |
| | | .el-table__empty-block { |
| | | padding: 40px 0; |
| | | } |
| | | } |
| | | |
| | | .pagination-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | padding: 16px 20px; |
| | | background-color: #ffffff; |
| | | border-top: 1px solid #ebeef5; |
| | | border-radius: 0 0 12px 12px; |
| | | } |
| | | |
| | | :deep(.el-button) { |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | transform: translateY(-1px); |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog) { |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | |
| | | .el-dialog__header { |
| | | background-color: #fafafa; |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 20px 24px; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | .el-dialog__body { |
| | | padding: 24px; |
| | | } |
| | | |
| | | .el-dialog__footer { |
| | | padding: 16px 24px; |
| | | border-top: 1px solid #ebeef5; |
| | | background-color: #fafafa; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-form) { |
| | | .el-form-item { |
| | | margin-bottom: 20px; |
| | | |
| | | .el-form-item__label { |
| | | font-weight: 500; |
| | | color: #303133; |
| | | } |
| | | |
| | | .el-input, |
| | | .el-select, |
| | | .el-date-picker, |
| | | .el-input-number { |
| | | width: 100%; |
| | | |
| | | // .el-input__inner { |
| | | // border-radius: 6px; |
| | | // border: 1px solid #dcdfe6; |
| | | // transition: all 0.3s ease; |
| | | |
| | | // &:focus { |
| | | // border-color: #409eff; |
| | | // box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2); |
| | | // } |
| | | // } |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep(.el-tag) { |
| | | border-radius: 4px; |
| | | padding: 2px 8px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .app-container { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .search_form { |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | gap: 12px; |
| | | |
| | | .el-form { |
| | | width: 100%; |
| | | |
| | | .el-form-item { |
| | | width: 100%; |
| | | } |
| | | } |
| | | |
| | | > div { |
| | | width: 100%; |
| | | display: flex; |
| | | gap: 12px; |
| | | |
| | | .el-button { |
| | | flex: 1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | th, |
| | | td { |
| | | padding: 10px 0; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog) { |
| | | width: 90% !important; |
| | | margin: 20px auto !important; |
| | | } |
| | | } |
| | | .consumption-value { |
| | | font-weight: bold; |
| | | color: #409eff; |
| | | } |
| | | |
| | | .consumption-unit { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | margin-left: 4px; |
| | | } |
| | | .search_form { |
| | | :deep(.el-form-item) { |
| | | margin-bottom: 0px !important; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | height="calc(100vh - 350px)" |
| | | :tableLoading="tableLoading" |
| | | :isSelection="true" |
| | | :selectable="isSelectable" |
| | |
| | | width="500px"> |
| | | <el-form :model="mergeForm" |
| | | label-width="120px"> |
| | | <el-form-item label="ç产计åå·"> |
| | | <el-input v-model="mergeForm.productionPlanNo" |
| | | <el-form-item label="åºåå·"> |
| | | <el-input v-model="mergeForm.serialNo" |
| | | disabled /> |
| | | </el-form-item> |
| | | <el-form-item label="çäº§è®¡åæ°é"> |
| | | <el-input-number v-model="mergeForm.totalManufactureQuantity" |
| | | <el-input-number v-model="mergeForm.totalquantity" |
| | | :min="1" |
| | | :step="1" |
| | | style="width: 100%" /> |
| | |
| | | <el-table :data="categorySummary" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column prop="productCategory" |
| | | <el-table-column prop="materialCategory" |
| | | label="产åç±»å«" |
| | | align="center" |
| | | width="150" /> |
| | | <el-table-column prop="totalManufactureQuantity" |
| | | <el-table-column prop="totalquantity" |
| | | label="æ»å¶é æ°é" |
| | | align="center" /> |
| | | </el-table> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="showCategorySummaryDialog = false">å
³é</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 追踪è¿åº¦å¼¹çª --> |
| | | <el-dialog v-model="showTrackProgressDialog" |
| | | :title="`追踪è¿åº¦ - ${trackProgressForm.serialNo || ''}`" |
| | | width="600px"> |
| | | <el-form :model="trackProgressForm" |
| | | label-width="120px"> |
| | | <el-form-item label="åºåå·"> |
| | | <el-input v-model="trackProgressForm.serialNo" |
| | | disabled /> |
| | | </el-form-item> |
| | | <el-form-item label="å½åç¶æ"> |
| | | <el-select v-model="trackProgressForm.currentStatus" |
| | | placeholder="è¯·éæ©ç¶æ"> |
| | | <el-option label="å¾
å¤ç" |
| | | value="pending" /> |
| | | <el-option label="è¿è¡ä¸" |
| | | value="processing" /> |
| | | <el-option label="已宿" |
| | | value="completed" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="宿è¿åº¦"> |
| | | <el-progress :percentage="trackProgressForm.completionRate" |
| | | :status="trackProgressForm.completionRate === 100 ? 'success' : ''" /> |
| | | </el-form-item> |
| | | <el-form-item label="è¿åº¦è¯¦æ
"> |
| | | <el-table :data="trackProgressForm.progressDetails" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column prop="step" |
| | | label="æ¥éª¤" |
| | | align="center" |
| | | width="100" /> |
| | | <el-table-column prop="status" |
| | | label="ç¶æ" |
| | | align="center" |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'completed' ? 'success' : scope.row.status === 'processing' ? 'warning' : 'info'"> |
| | | {{ scope.row.status === 'completed' ? '已宿' : scope.row.status === 'processing' ? 'è¿è¡ä¸' : 'å¾
å¼å§' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="startTime" |
| | | label="å¼å§æ¶é´" |
| | | align="center" |
| | | width="180" /> |
| | | <el-table-column prop="endTime" |
| | | label="ç»ææ¶é´" |
| | | align="center" |
| | | width="180" /> |
| | | </el-table> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨"> |
| | | <el-input v-model="trackProgressForm.remark" |
| | | type="textarea" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="showTrackProgressDialog = false">å
³é</el-button> |
| | | <el-button type="primary" |
| | | @click="handleUpdateProgress">æ´æ°è¿åº¦</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | |
| | | import { onMounted, ref } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import { productOrderListPage } from "@/api/productionManagement/productionOrder.js"; |
| | | import { productionPlanListPage } from "@/api/productionPlan/productionPlan.js"; |
| | | import PIMTable from "./components/PIMTable.vue"; |
| | | |
| | | const tableColumn = ref([ |
| | |
| | | width: "120px", |
| | | }, |
| | | { |
| | | label: "ç产计åå·", |
| | | prop: "productionPlanNo", |
| | | label: "åºåå·", |
| | | prop: "serialNo", |
| | | width: "140px", |
| | | }, |
| | | { |
| | |
| | | }, |
| | | { |
| | | label: "产åç±»å«", |
| | | prop: "productCategory", |
| | | prop: "materialCategory", |
| | | width: "100px", |
| | | }, |
| | | { |
| | |
| | | }, |
| | | { |
| | | label: "å¶é æ°é", |
| | | prop: "manufactureQuantity", |
| | | prop: "quantity", |
| | | width: "100px", |
| | | align: "right", |
| | | }, |
| | |
| | | clickFun: row => { |
| | | // åç¬ä¸åæä½ |
| | | // è®¾ç½®è¡¨åæ°æ® |
| | | mergeForm.productionPlanNo = row.productionPlanNo; |
| | | mergeForm.totalManufactureQuantity = row.manufactureQuantity; |
| | | mergeForm.serialNo = row.serialNo; |
| | | mergeForm.totalquantity = row.quantity; |
| | | mergeForm.remark = ""; |
| | | |
| | | // æå¼å¼¹çª |
| | |
| | | name: "追踪è¿åº¦", |
| | | type: "text", |
| | | clickFun: row => { |
| | | // 追踪è¿åº¦æä½ |
| | | ElMessage.warning("追踪è¿åº¦åè½å¾
å¼å"); |
| | | handleTrackProgress(row); |
| | | }, |
| | | }, |
| | | ], |
| | |
| | | const isShowNewModal = ref(false); |
| | | // åå¹¶ä¸åè¡¨åæ°æ® |
| | | const mergeForm = reactive({ |
| | | productionPlanNo: "", |
| | | totalManufactureQuantity: 0, |
| | | serialNo: "", |
| | | totalquantity: 0, |
| | | remark: "", |
| | | }); |
| | | |
| | | // 追踪è¿åº¦å¼¹çªæ§å¶ |
| | | const showTrackProgressDialog = ref(false); |
| | | // 追踪è¿åº¦è¡¨åæ°æ® |
| | | const trackProgressForm = reactive({ |
| | | serialNo: "", |
| | | currentStatus: "", |
| | | completionRate: 0, |
| | | progressDetails: [], |
| | | remark: "", |
| | | }); |
| | | |
| | | // å¤ç追踪è¿åº¦æé®ç¹å» |
| | | const handleTrackProgress = row => { |
| | | // è®¾ç½®è¡¨åæ°æ® |
| | | trackProgressForm.serialNo = row.serialNo; |
| | | trackProgressForm.currentStatus = row.status; |
| | | |
| | | // çææ¨¡æè¿åº¦æ°æ® |
| | | trackProgressForm.progressDetails = generateProgressDetails(row.status); |
| | | |
| | | // 计ç®å®æç |
| | | trackProgressForm.completionRate = calculateCompletionRate( |
| | | trackProgressForm.progressDetails |
| | | ); |
| | | trackProgressForm.remark = ""; |
| | | |
| | | // æå¼å¼¹çª |
| | | showTrackProgressDialog.value = true; |
| | | }; |
| | | |
| | | // çææ¨¡æè¿åº¦è¯¦æ
æ°æ® |
| | | const generateProgressDetails = status => { |
| | | const details = [ |
| | | { |
| | | step: "计å确认", |
| | | status: "completed", |
| | | startTime: "2026-03-01 09:00:00", |
| | | endTime: "2026-03-01 10:00:00", |
| | | }, |
| | | { |
| | | step: "ç©æåå¤", |
| | | status: |
| | | status === "completed" |
| | | ? "completed" |
| | | : status === "processing" |
| | | ? "completed" |
| | | : "pending", |
| | | startTime: |
| | | status === "completed" || status === "processing" |
| | | ? "2026-03-01 10:30:00" |
| | | : "", |
| | | endTime: |
| | | status === "completed" || status === "processing" |
| | | ? "2026-03-02 16:00:00" |
| | | : "", |
| | | }, |
| | | { |
| | | step: "ç产å å·¥", |
| | | status: |
| | | status === "completed" |
| | | ? "completed" |
| | | : status === "processing" |
| | | ? "processing" |
| | | : "pending", |
| | | startTime: |
| | | status === "completed" || status === "processing" |
| | | ? "2026-03-03 08:00:00" |
| | | : "", |
| | | endTime: status === "completed" ? "2026-03-08 17:00:00" : "", |
| | | }, |
| | | { |
| | | step: "è´¨éæ£éª", |
| | | status: status === "completed" ? "completed" : "pending", |
| | | startTime: status === "completed" ? "2026-03-09 09:00:00" : "", |
| | | endTime: status === "completed" ? "2026-03-09 15:00:00" : "", |
| | | }, |
| | | { |
| | | step: "å
¥åº", |
| | | status: status === "completed" ? "completed" : "pending", |
| | | startTime: status === "completed" ? "2026-03-10 10:00:00" : "", |
| | | endTime: status === "completed" ? "2026-03-10 11:00:00" : "", |
| | | }, |
| | | ]; |
| | | return details; |
| | | }; |
| | | |
| | | // 计ç®å®æç |
| | | const calculateCompletionRate = details => { |
| | | const completedSteps = details.filter( |
| | | step => step.status === "completed" |
| | | ).length; |
| | | return Math.round((completedSteps / details.length) * 100); |
| | | }; |
| | | |
| | | // å¤çè¿åº¦æ´æ° |
| | | const handleUpdateProgress = () => { |
| | | // è¿éå¯ä»¥æ·»å æ´æ°è¿åº¦çé»è¾ |
| | | ElMessage.success("è¿åº¦æ´æ°æå"); |
| | | showTrackProgressDialog.value = false; |
| | | }; |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | customerName: "", |
| | | salesContractNo: "", |
| | | projectName: "", |
| | | productCategory: "", |
| | | materialCategory: "", |
| | | specificationModel: "", |
| | | }, |
| | | }); |
| | |
| | | |
| | | // éåè¡¨æ ¼æ°æ®ï¼æäº§åç±»å«æ±æ» |
| | | tableData.value.forEach(row => { |
| | | const category = row.productCategory; |
| | | const category = row.materialCategory; |
| | | if (!summary[category]) { |
| | | summary[category] = { |
| | | productCategory: category, |
| | | totalManufactureQuantity: 0, |
| | | materialCategory: category, |
| | | totalquantity: 0, |
| | | }; |
| | | } |
| | | summary[category].totalManufactureQuantity += row.manufactureQuantity; |
| | | summary[category].totalquantity += row.quantity; |
| | | }); |
| | | |
| | | // 转æ¢ä¸ºæ°ç»æ ¼å¼ |
| | |
| | | // æé ä¸ä¸ªæ°ç对象ï¼ä¸å
å«entryDateåæ®µ |
| | | const params = { ...searchForm.value, ...page }; |
| | | params.entryDate = undefined; |
| | | tableData.value = [ |
| | | { |
| | | id: 1, |
| | | source: "éå®è®¢å", |
| | | status: "å¾
å¤ç", |
| | | auditStatus: "å·²å®¡æ ¸", |
| | | orderNo: "SO20260301001", |
| | | productionPlanNo: "PP20260301001", |
| | | partNo: "P001", |
| | | partName: "é¶ä»¶A", |
| | | productCategory: "ç±»å«1", |
| | | processFileNo: "PF20260301001", |
| | | salesQuantity: 100, |
| | | manufactureQuantity: 105, |
| | | partUnit: "个", |
| | | mainPlanDemandDate: "2026-03-15", |
| | | commitmentDate: "2026-03-10", |
| | | manufactureProperty: "常è§", |
| | | remark: "", |
| | | updateTime: "2026-03-01", |
| | | updateBy: "admin", |
| | | createTime: "2026-03-01", |
| | | createBy: "admin", |
| | | }, |
| | | { |
| | | id: 2, |
| | | source: "éå®è®¢å", |
| | | status: "å¾
å¤ç", |
| | | auditStatus: "å·²å®¡æ ¸", |
| | | orderNo: "SO20260301002", |
| | | productionPlanNo: "PP20260301001", |
| | | partNo: "P002", |
| | | partName: "é¶ä»¶B", |
| | | productCategory: "ç±»å«1", |
| | | processFileNo: "PF20260301002", |
| | | salesQuantity: 200, |
| | | manufactureQuantity: 210, |
| | | partUnit: "个", |
| | | mainPlanDemandDate: "2026-03-15", |
| | | commitmentDate: "2026-03-10", |
| | | manufactureProperty: "常è§", |
| | | remark: "", |
| | | updateTime: "2026-03-01", |
| | | updateBy: "admin", |
| | | createTime: "2026-03-01", |
| | | createBy: "admin", |
| | | }, |
| | | { |
| | | id: 3, |
| | | source: "éå®è®¢å", |
| | | status: "è¿è¡ä¸", |
| | | auditStatus: "å·²å®¡æ ¸", |
| | | orderNo: "SO20260301003", |
| | | productionPlanNo: "PP20260301002", |
| | | partNo: "P003", |
| | | partName: "é¶ä»¶C", |
| | | productCategory: "ç±»å«2", |
| | | processFileNo: "PF20260301003", |
| | | salesQuantity: 150, |
| | | manufactureQuantity: 155, |
| | | partUnit: "个", |
| | | mainPlanDemandDate: "2026-03-20", |
| | | commitmentDate: "2026-03-15", |
| | | manufactureProperty: "常è§", |
| | | remark: "", |
| | | updateTime: "2026-03-01", |
| | | updateBy: "admin", |
| | | createTime: "2026-03-01", |
| | | createBy: "admin", |
| | | }, |
| | | { |
| | | id: 4, |
| | | source: "éå®è®¢å", |
| | | status: "è¿è¡ä¸", |
| | | auditStatus: "å·²å®¡æ ¸", |
| | | orderNo: "SO20260301004", |
| | | productionPlanNo: "PP20260301002", |
| | | partNo: "P004", |
| | | partName: "é¶ä»¶D", |
| | | productCategory: "ç±»å«2", |
| | | processFileNo: "PF20260301004", |
| | | salesQuantity: 300, |
| | | manufactureQuantity: 315, |
| | | partUnit: "个", |
| | | mainPlanDemandDate: "2026-03-20", |
| | | commitmentDate: "2026-03-15", |
| | | manufactureProperty: "常è§", |
| | | remark: "", |
| | | updateTime: "2026-03-01", |
| | | updateBy: "admin", |
| | | createTime: "2026-03-01", |
| | | createBy: "admin", |
| | | }, |
| | | { |
| | | id: 5, |
| | | source: "éå®è®¢å", |
| | | status: "已宿", |
| | | auditStatus: "å·²å®¡æ ¸", |
| | | orderNo: "SO20260301005", |
| | | productionPlanNo: "PP20260301003", |
| | | partNo: "P005", |
| | | partName: "é¶ä»¶E", |
| | | productCategory: "ç±»å«3", |
| | | processFileNo: "PF20260301005", |
| | | salesQuantity: 250, |
| | | manufactureQuantity: 260, |
| | | partUnit: "个", |
| | | mainPlanDemandDate: "2026-03-10", |
| | | commitmentDate: "2026-03-05", |
| | | manufactureProperty: "常è§", |
| | | remark: "", |
| | | updateTime: "2026-03-01", |
| | | updateBy: "admin", |
| | | createTime: "2026-03-01", |
| | | createBy: "admin", |
| | | }, |
| | | ]; |
| | | tableLoading.value = false; |
| | | page.total = tableData.value.length; |
| | | // 计ç®äº§åç±»å«æ±æ»ç»è®¡ |
| | | calculateCategorySummary(); |
| | | // productOrderListPage(params) |
| | | // .then(res => { |
| | | // tableData.value = [ |
| | | // { |
| | | // id: 1, |
| | | // source: "éå®è®¢å", |
| | | // status: "å¾
å¤ç", |
| | | // auditStatus: "å·²å®¡æ ¸", |
| | | // orderNo: "SO20260301001", |
| | | // serialNo: "PP20260301001", |
| | | // partNo: "P001", |
| | | // partName: "é¶ä»¶A", |
| | | // materialCategory: "ç±»å«1", |
| | | // processFileNo: "PF20260301001", |
| | | // salesQuantity: 100, |
| | | // quantity: 105, |
| | | // partUnit: "个", |
| | | // mainPlanDemandDate: "2026-03-15", |
| | | // commitmentDate: "2026-03-10", |
| | | // manufactureProperty: "常è§", |
| | | // remark: "", |
| | | // updateTime: "2026-03-01", |
| | | // updateBy: "admin", |
| | | // createTime: "2026-03-01", |
| | | // createBy: "admin", |
| | | // }, |
| | | // { |
| | | // id: 2, |
| | | // source: "éå®è®¢å", |
| | | // status: "å¾
å¤ç", |
| | | // auditStatus: "å·²å®¡æ ¸", |
| | | // orderNo: "SO20260301002", |
| | | // serialNo: "PP20260301001", |
| | | // partNo: "P002", |
| | | // partName: "é¶ä»¶B", |
| | | // materialCategory: "ç±»å«1", |
| | | // processFileNo: "PF20260301002", |
| | | // salesQuantity: 200, |
| | | // quantity: 210, |
| | | // partUnit: "个", |
| | | // mainPlanDemandDate: "2026-03-15", |
| | | // commitmentDate: "2026-03-10", |
| | | // manufactureProperty: "常è§", |
| | | // remark: "", |
| | | // updateTime: "2026-03-01", |
| | | // updateBy: "admin", |
| | | // createTime: "2026-03-01", |
| | | // createBy: "admin", |
| | | // }, |
| | | // { |
| | | // id: 3, |
| | | // source: "éå®è®¢å", |
| | | // status: "è¿è¡ä¸", |
| | | // auditStatus: "å·²å®¡æ ¸", |
| | | // orderNo: "SO20260301003", |
| | | // serialNo: "PP20260301002", |
| | | // partNo: "P003", |
| | | // partName: "é¶ä»¶C", |
| | | // materialCategory: "ç±»å«2", |
| | | // processFileNo: "PF20260301003", |
| | | // salesQuantity: 150, |
| | | // quantity: 155, |
| | | // partUnit: "个", |
| | | // mainPlanDemandDate: "2026-03-20", |
| | | // commitmentDate: "2026-03-15", |
| | | // manufactureProperty: "常è§", |
| | | // remark: "", |
| | | // updateTime: "2026-03-01", |
| | | // updateBy: "admin", |
| | | // createTime: "2026-03-01", |
| | | // createBy: "admin", |
| | | // }, |
| | | // { |
| | | // id: 4, |
| | | // source: "éå®è®¢å", |
| | | // status: "è¿è¡ä¸", |
| | | // auditStatus: "å·²å®¡æ ¸", |
| | | // orderNo: "SO20260301004", |
| | | // serialNo: "PP20260301002", |
| | | // partNo: "P004", |
| | | // partName: "é¶ä»¶D", |
| | | // materialCategory: "ç±»å«2", |
| | | // processFileNo: "PF20260301004", |
| | | // salesQuantity: 300, |
| | | // quantity: 315, |
| | | // partUnit: "个", |
| | | // mainPlanDemandDate: "2026-03-20", |
| | | // commitmentDate: "2026-03-15", |
| | | // manufactureProperty: "常è§", |
| | | // remark: "", |
| | | // updateTime: "2026-03-01", |
| | | // updateBy: "admin", |
| | | // createTime: "2026-03-01", |
| | | // createBy: "admin", |
| | | // }, |
| | | // { |
| | | // id: 5, |
| | | // source: "éå®è®¢å", |
| | | // status: "已宿", |
| | | // auditStatus: "å·²å®¡æ ¸", |
| | | // orderNo: "SO20260301005", |
| | | // serialNo: "PP20260301003", |
| | | // partNo: "P005", |
| | | // partName: "é¶ä»¶E", |
| | | // materialCategory: "ç±»å«3", |
| | | // processFileNo: "PF20260301005", |
| | | // salesQuantity: 250, |
| | | // quantity: 260, |
| | | // partUnit: "个", |
| | | // mainPlanDemandDate: "2026-03-10", |
| | | // commitmentDate: "2026-03-05", |
| | | // manufactureProperty: "常è§", |
| | | // remark: "", |
| | | // updateTime: "2026-03-01", |
| | | // updateBy: "admin", |
| | | // createTime: "2026-03-01", |
| | | // createBy: "admin", |
| | | // }, |
| | | // ]; |
| | | // tableLoading.value = false; |
| | | |
| | | // tableData.value = res.data.records; |
| | | // page.total = res.data.total; |
| | | // page.total = tableData.value.length; |
| | | // // 计ç®äº§åç±»å«æ±æ»ç»è®¡ |
| | | // calculateCategorySummary(); |
| | | // }) |
| | | // .catch(() => { |
| | | // tableLoading.value = false; |
| | | // }); |
| | | productionPlanListPage(params) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | // 计ç®äº§åç±»å«æ±æ»ç»è®¡ |
| | | calculateCategorySummary(); |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | // éä¸çç产计åå· |
| | | const selectedProductionPlanNo = ref(""); |
| | | // éä¸çåºåå· |
| | | const selectedserialNo = ref(""); |
| | | |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | // 妿æéä¸çè¡ï¼è®°å½ç¬¬ä¸ä¸ªéä¸è¡çç产计åå· |
| | | // 妿æéä¸çè¡ï¼è®°å½ç¬¬ä¸ä¸ªéä¸è¡çåºåå· |
| | | if (selection.length > 0) { |
| | | selectedProductionPlanNo.value = selection[0].productionPlanNo; |
| | | selectedserialNo.value = selection[0].serialNo; |
| | | } else { |
| | | // å¦ææ²¡æéä¸çè¡ï¼æ¸
空ç产计åå· |
| | | selectedProductionPlanNo.value = ""; |
| | | // å¦ææ²¡æéä¸çè¡ï¼æ¸
空åºåå· |
| | | selectedserialNo.value = ""; |
| | | } |
| | | }; |
| | | |
| | | // å¤æè¡æ¯å¦å¯éæ© |
| | | const isSelectable = row => { |
| | | // å¦ææ²¡æéä¸çè¡ï¼ææè¡é½å¯éæ© |
| | | if (!selectedProductionPlanNo.value) { |
| | | if (!selectedserialNo.value) { |
| | | return true; |
| | | } |
| | | // 妿æéä¸çè¡ï¼åªæç产计åå·ç¸åçè¡æå¯éæ© |
| | | return row.productionPlanNo === selectedProductionPlanNo.value; |
| | | // 妿æéä¸çè¡ï¼åªæåºåå·ç¸åçè¡æå¯éæ© |
| | | return row.serialNo === selectedserialNo.value; |
| | | }; |
| | | |
| | | // å¤çåå¹¶ä¸åæé®ç¹å» |
| | |
| | | |
| | | // è®¡ç®æ»å¶é æ°é |
| | | const totalQuantity = selectedRows.value.reduce((sum, row) => { |
| | | return sum + row.manufactureQuantity; |
| | | return sum + row.quantity; |
| | | }, 0); |
| | | |
| | | // è®¾ç½®è¡¨åæ°æ® |
| | | mergeForm.productionPlanNo = selectedProductionPlanNo.value; |
| | | mergeForm.totalManufactureQuantity = totalQuantity; |
| | | mergeForm.serialNo = selectedserialNo.value; |
| | | mergeForm.totalquantity = totalQuantity; |
| | | mergeForm.remark = ""; |
| | | |
| | | // æå¼å¼¹çª |
| | |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .app-container { |
| | | padding: 24px; |
| | | background-color: #f0f2f5; |
| | | min-height: calc(100vh - 48px); |
| | | } |
| | | |
| | | .search_form { |
| | | align-items: start; |
| | | } |
| | | |
| | | .summary-section { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .horizontal-summary { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 20px; |
| | | padding: 10px 0; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 24px; |
| | | padding: 20px; |
| | | background-color: #ffffff; |
| | | border-radius: 6px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08); |
| | | } |
| | | } |
| | | |
| | | .summary-item { |
| | | flex: 1; |
| | | min-width: 120px; |
| | | text-align: center; |
| | | padding: 10px; |
| | | .table_list { |
| | | // margin-bottom: 24px; |
| | | background-color: #ffffff; |
| | | border-radius: 6px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); |
| | | overflow: hidden; |
| | | height: calc(100vh - 250px); |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | border: none; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | |
| | | .el-table__header-wrapper { |
| | | background-color: #fafafa; |
| | | |
| | | th { |
| | | background-color: #fafafa; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 14px 0; |
| | | } |
| | | } |
| | | |
| | | .el-table__body-wrapper { |
| | | tr { |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | background-color: #f5f7fa; |
| | | border-radius: 4px; |
| | | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .summary-label { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | margin-bottom: 5px; |
| | | td { |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 12px 0; |
| | | } |
| | | } |
| | | |
| | | .summary-value { |
| | | font-size: 18px; |
| | | tr.current-row { |
| | | background-color: #ecf5ff; |
| | | } |
| | | } |
| | | |
| | | .el-table__empty-block { |
| | | padding: 40px 0; |
| | | } |
| | | } |
| | | |
| | | .pagination-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | padding: 16px 20px; |
| | | background-color: #ffffff; |
| | | border-top: 1px solid #ebeef5; |
| | | border-radius: 0 0 12px 12px; |
| | | } |
| | | |
| | | :deep(.el-button) { |
| | | transition: all 0.3s ease; |
| | | |
| | | &:hover { |
| | | transform: translateY(-1px); |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog) { |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | |
| | | .el-dialog__header { |
| | | background-color: #fafafa; |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 20px 24px; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | |
| | | ::v-deep .yellow { |
| | | background-color: #faf0de; |
| | | } |
| | | |
| | | ::v-deep .pink { |
| | | background-color: #fae1de; |
| | | .el-dialog__body { |
| | | padding: 24px; |
| | | } |
| | | |
| | | ::v-deep .red { |
| | | background-color: #f80202; |
| | | .el-dialog__footer { |
| | | padding: 16px 24px; |
| | | border-top: 1px solid #ebeef5; |
| | | background-color: #fafafa; |
| | | } |
| | | } |
| | | |
| | | ::v-deep .purple { |
| | | background-color: #f4defa; |
| | | :deep(.el-form) { |
| | | .el-form-item { |
| | | margin-bottom: 20px; |
| | | |
| | | .el-form-item__label { |
| | | font-weight: 500; |
| | | color: #303133; |
| | | } |
| | | |
| | | .el-input, |
| | | .el-select, |
| | | .el-date-picker, |
| | | .el-input-number { |
| | | width: 100%; |
| | | |
| | | // .el-input__inner { |
| | | // border-radius: 6px; |
| | | // border: 1px solid #dcdfe6; |
| | | // transition: all 0.3s ease; |
| | | |
| | | // &:focus { |
| | | // border-color: #409eff; |
| | | // box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2); |
| | | // } |
| | | // } |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep(.el-tag) { |
| | | border-radius: 4px; |
| | | padding: 2px 8px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .app-container { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .search_form { |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | gap: 12px; |
| | | |
| | | .el-form { |
| | | width: 100%; |
| | | |
| | | .el-form-item { |
| | | width: 100%; |
| | | } |
| | | } |
| | | |
| | | > div { |
| | | width: 100%; |
| | | display: flex; |
| | | gap: 12px; |
| | | |
| | | .el-button { |
| | | flex: 1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | th, |
| | | td { |
| | | padding: 10px 0; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog) { |
| | | width: 90% !important; |
| | | margin: 20px auto !important; |
| | | } |
| | | } |
| | | .consumption-value { |
| | | font-weight: bold; |
| | | color: #409eff; |
| | | } |
| | | |
| | | .consumption-unit { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | margin-left: 4px; |
| | | } |
| | | .search_form { |
| | | :deep(.el-form-item) { |
| | | margin-bottom: 0px !important; |
| | | } |
| | | } |
| | | </style> |