| | |
| | | <!-- 使用通用页面头部组件 --> |
| | | <PageHeader title="生产派工" @back="goBack" /> |
| | | |
| | | <!-- 炒机状态展示 --> |
| | | <view class="machines-section"> |
| | | <view class="section-title">炒机状态</view> |
| | | <view class="machines-grid"> |
| | | <view v-for="machine in machines" :key="machine.id" class="machine-card"> |
| | | <view class="machine-title">炒机{{ machine.id }}</view> |
| | | <view class="machine-metrics"> |
| | | <view class="metric-item"> |
| | | <text class="metric-label">总量(kg)</text> |
| | | <up-input |
| | | v-model="machineTotal[machine.key]" |
| | | type="number" |
| | | placeholder="请输入总量" |
| | | border="surround" |
| | | size="mini" |
| | | class="metric-input" |
| | | @change="updateMachineVacant(machine.key)" |
| | | /> |
| | | </view> |
| | | <view class="metric-item"> |
| | | <text class="metric-label">正在生产(kg)</text> |
| | | <text class="metric-value">{{ machineInProduction[machine.key] }}</text> |
| | | </view> |
| | | <view class="metric-item"> |
| | | <text class="metric-label">空余量(kg)</text> |
| | | <text class="metric-value">{{ machineVacant[machine.key] }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view class="save-section"> |
| | | <up-button type="primary" @click="saveMachineTotals" size="normal" class="save-btn">保存炒机设置</up-button> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 搜索区域 --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <view class="search-form"> |
| | | <view class="search-item"> |
| | | <text class="search-label">客户名称</text> |
| | | <up-input |
| | | class="search-text" |
| | | placeholder="请输入客户名称搜索" |
| | | v-model="searchForm.customerName" |
| | | placeholder="请输入客户名称" |
| | | @change="handleQuery" |
| | | clearable |
| | | border="surround" |
| | | class="search-input" |
| | | /> |
| | | </view> |
| | | <view class="filter-button" @click="handleQuery"> |
| | | <up-icon name="search" size="24" color="#999"></up-icon> |
| | | <view class="search-item"> |
| | | <text class="search-label">项目名称</text> |
| | | <up-input |
| | | v-model="searchForm.projectName" |
| | | placeholder="请输入项目名称" |
| | | @change="handleQuery" |
| | | clearable |
| | | border="surround" |
| | | class="search-input" |
| | | /> |
| | | </view> |
| | | <view class="search-buttons"> |
| | | <up-button type="primary" @click="handleQuery" size="small" class="search-btn">搜索</up-button> |
| | | <up-button @click="handleReset" size="small" class="reset-btn">重置</up-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 批量操作区域 --> |
| | | <view v-if="showBatchActions" class="batch-actions-section"> |
| | | <view class="batch-info"> |
| | | <text class="batch-count">已选择 {{ selectedItems.length }} 个项目</text> |
| | | </view> |
| | | <view class="batch-buttons"> |
| | | <up-button type="primary" size="small" @click="handleAutoDispatch" class="batch-btn"> |
| | | <up-icon name="play-circle" size="16" color="#ffffff"></up-icon> |
| | | 自动派单 |
| | | </up-button> |
| | | <up-button type="default" size="small" @click="clearSelection" class="batch-btn"> |
| | | <up-icon name="close-circle" size="16" color="#6c757d"></up-icon> |
| | | 取消选择 |
| | | </up-button> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 全选操作区域 --> |
| | | <view v-if="tableData.length > 0" class="select-all-section"> |
| | | <view class="select-all-checkbox" @click="toggleAllSelection"> |
| | | <up-icon |
| | | :name="isAllSelected ? 'checkbox-mark' : 'circle'" |
| | | :color="isAllSelected ? '#409eff' : '#c0c4cc'" |
| | | size="18" |
| | | ></up-icon> |
| | | <text class="select-all-text">{{ isAllSelected ? '取消全选' : '全选' }}</text> |
| | | </view> |
| | | <text class="select-all-hint">(仅选择待排数量大于0的项目)</text> |
| | | </view> |
| | | |
| | | <!-- 生产派工列表 --> |
| | | <view class="ledger-list" v-if="tableData.length > 0"> |
| | | <view v-for="(item, index) in tableData" :key="item.id || index"> |
| | | <view v-for="(item, index) in tableData" :key="item.id || index" class="list-item"> |
| | | <view class="ledger-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" size="16" color="#ffffff"></up-icon> |
| | | <!-- 选择复选框 --> |
| | | <view class="item-checkbox" @click="toggleItemSelection(item)"> |
| | | <up-icon |
| | | :name="selectedItems.includes(item.id) ? 'checkbox-mark' : 'circle'" |
| | | :color="selectedItems.includes(item.id) ? '#409eff' : '#c0c4cc'" |
| | | size="18" |
| | | ></up-icon> |
| | | </view> |
| | | |
| | | <view class="item-content"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" size="16" color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.salesContractNo }}</text> |
| | | </view> |
| | | <text class="item-id">{{ item.salesContractNo }}</text> |
| | | <text class="entry-date">{{ item.entryDate }}</text> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">录入日期</text> |
| | | <text class="detail-value">{{ item.entryDate }}</text> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客户合同号</text> |
| | | <text class="detail-value">{{ item.customerContractNo }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客户名称</text> |
| | | <text class="detail-value">{{ item.customerName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">项目名称</text> |
| | | <text class="detail-value">{{ item.projectName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">产品大类</text> |
| | | <text class="detail-value">{{ item.productCategory }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">规格型号</text> |
| | | <text class="detail-value">{{ item.specificationModel }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">单位</text> |
| | | <text class="detail-value">{{ item.unit }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">总数量</text> |
| | | <text class="detail-value">{{ item.quantity }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">排产数量</text> |
| | | <text class="detail-value highlight">{{ item.schedulingNum }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">待排数量</text> |
| | | <text class="detail-value" :class="{ 'danger': item.pendingQuantity <= 0 }">{{ item.pendingQuantity }}</text> |
| | | </view> |
| | | |
| | | <!-- 操作按钮区域 --> |
| | | <view class="action-buttons"> |
| | | <up-button |
| | | type="primary" |
| | | size="small" |
| | | @click="handleDispatch(item)" |
| | | class="action-btn" |
| | | :disabled="item.pendingQuantity <= 0" |
| | | > |
| | | {{ item.pendingQuantity <= 0 ? '无需派工' : '生产派工' }} |
| | | </up-button> |
| | | </view> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客户合同号</text> |
| | | <text class="detail-value">{{ item.customerContractNo }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客户名称</text> |
| | | <text class="detail-value">{{ item.customerName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">项目名称</text> |
| | | <text class="detail-value">{{ item.projectName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">产品大类</text> |
| | | <text class="detail-value">{{ item.productCategory }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">规格型号</text> |
| | | <text class="detail-value">{{ item.specificationModel }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">总数量</text> |
| | | <text class="detail-value">{{ item.quantity }} {{ item.unit }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">排产数量</text> |
| | | <text class="detail-value highlight">{{ item.schedulingNum }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">待排数量</text> |
| | | <text class="detail-value" :class="{ 'danger': item.pendingQuantity <= 0 }">{{ item.pendingQuantity }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 操作按钮区域 --> |
| | | <view class="action-buttons"> |
| | | <up-button |
| | | type="primary" |
| | | size="small" |
| | | @click="handleDispatch(item)" |
| | | class="action-btn" |
| | | :disabled="item.pendingQuantity <= 0" |
| | | > |
| | | 生产派工 |
| | | </up-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view v-else class="no-data"> |
| | | <text>暂无生产派工数据</text> |
| | | <up-empty mode="data" icon="http://cdn.uviewui.com/uview/empty/data.png"> |
| | | <text class="no-data-text">暂无生产派工数据</text> |
| | | </up-empty> |
| | | </view> |
| | | |
| | | <!-- 派工弹窗 --> |
| | |
| | | import { ref, reactive, toRefs, getCurrentInstance } from "vue"; |
| | | import { onShow } from '@dcloudio/uni-app'; |
| | | import dayjs from "dayjs"; |
| | | import {schedulingListPage} from "@/api/productionManagement/productionOrder.js"; |
| | | import {schedulingListPage, schedulingList, addSpeculatTrading, updateSpeculatTrading} from "@/api/productionManagement/productionOrder.js"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import DispatchModal from "./components/DispatchModal.vue"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | // 加载状态 |
| | |
| | | // 列表数据 |
| | | const tableData = ref([]); |
| | | |
| | | // 批量选择相关数据 |
| | | const selectedItems = ref([]); // 选中的项目ID数组 |
| | | const isAllSelected = ref(false); // 是否全选 |
| | | const showBatchActions = ref(false); // 是否显示批量操作区域 |
| | | |
| | | // 搜索表单数据 |
| | | const data = reactive({ |
| | | searchForm: { |
| | | customerName: "", |
| | | projectName: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // 分页配置 |
| | | const page = reactive({ |
| | | current: -1, |
| | | size: -1, |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | |
| | | // 炒机状态数据 |
| | | const machineTotal = reactive({ |
| | | m1: 0, |
| | | m2: 0, |
| | | m3: 0, |
| | | m4: 0, |
| | | }) |
| | | |
| | | const machineInProduction = reactive({ |
| | | m1: 0, |
| | | m2: 0, |
| | | m3: 0, |
| | | m4: 0, |
| | | }) |
| | | |
| | | const machineVacant = reactive({ |
| | | m1: 0, |
| | | m2: 0, |
| | | m3: 0, |
| | | m4: 0, |
| | | }) |
| | | |
| | | // 炒机配置数组 |
| | | const machines = [ |
| | | { id: 1, key: 'm1' }, |
| | | { id: 2, key: 'm2' }, |
| | | { id: 3, key: 'm3' }, |
| | | { id: 4, key: 'm4' } |
| | | ] |
| | | |
| | | // 是否有查询数据(用于判断是新增还是修改) |
| | | const hasQueryData = ref(false); |
| | | |
| | | // 派工弹窗引用 |
| | | const dispatchModalRef = ref(); |
| | |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // 重置搜索 |
| | | const handleReset = () => { |
| | | searchForm.value.customerName = ""; |
| | | searchForm.value.projectName = ""; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // 查询列表 |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | // 获取炒机生产数据 |
| | | const getMachineProductionData = () => { |
| | | schedulingList().then((res) => { |
| | | if (res.data && Array.isArray(res.data)) { |
| | | // 重置数据 |
| | | machineInProduction.m1 = 0; |
| | | machineInProduction.m2 = 0; |
| | | machineInProduction.m3 = 0; |
| | | machineInProduction.m4 = 0; |
| | | |
| | | // 处理炒机数据 |
| | | res.data.forEach(item => { |
| | | const machineId = Number(item.id); |
| | | if (machineId >= 1 && machineId <= 4) { |
| | | const machineKey = `m${machineId}`; |
| | | |
| | | if (item.workLoad !== null && item.workLoad !== undefined) { |
| | | machineTotal[machineKey] = Number(item.workLoad) || 0; |
| | | } |
| | | |
| | | if (item.currentWorkLoad !== null && item.currentWorkLoad !== undefined) { |
| | | machineInProduction[machineKey] = Number(item.currentWorkLoad) || 0; |
| | | } |
| | | |
| | | // 计算空余量 |
| | | machineVacant[machineKey] = machineTotal[machineKey] - machineInProduction[machineKey]; |
| | | } |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | console.error('获取炒机数据失败:', err); |
| | | }); |
| | | }; |
| | | |
| | | // 获取列表数据 |
| | |
| | | loading.value = true; |
| | | showLoadingToast('加载中...'); |
| | | |
| | | // 构造请求参数 |
| | | const params = { ...searchForm.value, ...page }; |
| | | |
| | | schedulingListPage(params).then((res) => { |
| | | loading.value = false; |
| | | closeToast(); |
| | | |
| | | // 处理每条数据,增加pendingQuantity字段 |
| | | tableData.value = (res.data.records || []).map(item => ({ |
| | | ...item, |
| | | pendingQuantity: (Number(item.quantity) || 0) - (Number(item.schedulingNum) || 0) |
| | | })); |
| | | |
| | | page.total = res.data.total || 0; |
| | | |
| | | // 获取炒机数据 |
| | | getMachineProductionData(); |
| | | |
| | | }).catch(() => { |
| | | loading.value = false; |
| | | closeToast(); |
| | |
| | | getList(); // 刷新列表 |
| | | }; |
| | | |
| | | // 更新炒机空余量 |
| | | const updateMachineVacant = (machineKey) => { |
| | | machineVacant[machineKey] = (Number(machineTotal[machineKey]) || 0) - (Number(machineInProduction[machineKey]) || 0); |
| | | }; |
| | | |
| | | // 获取炒机查询数据 |
| | | const getMachineQueryData = (machineId) => { |
| | | // 这里需要根据实际情况从查询数据中获取对应的炒机数据 |
| | | // 暂时返回一个模拟数据 |
| | | return { |
| | | id: machineId, |
| | | name: `炒机${machineId}`, |
| | | workLoad: machineTotal[`m${machineId}`] || 0, |
| | | currentWorkLoad: machineInProduction[`m${machineId}`] || 0 |
| | | }; |
| | | }; |
| | | |
| | | // 保存炒机总量设置 |
| | | const saveMachineTotals = () => { |
| | | // 构造保存数据数组,使用machines数组循环构建 |
| | | const saveData = machines.map(machine => { |
| | | const machineData = { |
| | | name: `炒机${machine.id}`, // 炒机名称 |
| | | workLoad: machineTotal[machine.key] || 0, // 总量 |
| | | vacant: machineVacant[machine.key] || 0 // 空余量 |
| | | }; |
| | | |
| | | // 如果是修改操作,需要传递id字段 |
| | | if (hasQueryData.value) { |
| | | // 这里需要从查询数据中获取对应的id |
| | | // 假设查询数据中每个炒机数据都有id字段 |
| | | const queryData = getMachineQueryData(machine.id); |
| | | if (queryData && queryData.id) { |
| | | machineData.id = queryData.id; |
| | | } |
| | | } |
| | | |
| | | return machineData; |
| | | }); |
| | | |
| | | console.log('保存炒机设置数据:', saveData); |
| | | |
| | | // 根据是否有查询数据决定调用新增接口还是修改接口 |
| | | const saveApi = hasQueryData.value ? updateSpeculatTrading : addSpeculatTrading; |
| | | const successMessage = hasQueryData.value ? '炒机设置修改成功' : '炒机设置新增成功'; |
| | | |
| | | console.log(`调用接口: ${hasQueryData.value ? '修改' : '新增'}`); |
| | | |
| | | // 调用后端API保存 |
| | | saveApi(saveData).then(res => { |
| | | proxy.$message.success(successMessage); |
| | | console.log('保存成功:', res); |
| | | |
| | | // 保存成功后,设置hasQueryData为true,下次保存将调用修改接口 |
| | | if (!hasQueryData.value) { |
| | | hasQueryData.value = true; |
| | | } |
| | | }).catch(err => { |
| | | proxy.$message.error('保存失败'); |
| | | console.error('保存失败:', err); |
| | | }); |
| | | }; |
| | | |
| | | // 批量选择相关函数 |
| | | |
| | | // 切换单个项目的选择状态 |
| | | const toggleItemSelection = (item) => { |
| | | const itemId = item.id; |
| | | const index = selectedItems.value.indexOf(itemId); |
| | | |
| | | if (index > -1) { |
| | | // 如果已选中,则取消选择 |
| | | selectedItems.value.splice(index, 1); |
| | | } else { |
| | | // 如果未选中,则添加选择 |
| | | selectedItems.value.push(itemId); |
| | | } |
| | | |
| | | // 更新全选状态 |
| | | updateAllSelectedStatus(); |
| | | // 更新批量操作区域显示状态 |
| | | updateBatchActionsVisibility(); |
| | | }; |
| | | |
| | | // 切换全选状态 |
| | | const toggleAllSelection = () => { |
| | | if (isAllSelected.value) { |
| | | // 取消全选 |
| | | selectedItems.value = []; |
| | | } else { |
| | | // 全选 |
| | | selectedItems.value = tableData.value |
| | | .filter(item => item.pendingQuantity > 0) // 只选择待排数量大于0的项目 |
| | | .map(item => item.id); |
| | | } |
| | | |
| | | isAllSelected.value = !isAllSelected.value; |
| | | updateBatchActionsVisibility(); |
| | | }; |
| | | |
| | | // 更新全选状态 |
| | | const updateAllSelectedStatus = () => { |
| | | const selectableItems = tableData.value.filter(item => item.pendingQuantity > 0); |
| | | if (selectableItems.length === 0) { |
| | | isAllSelected.value = false; |
| | | return; |
| | | } |
| | | |
| | | isAllSelected.value = selectedItems.value.length === selectableItems.length && |
| | | selectableItems.every(item => selectedItems.value.includes(item.id)); |
| | | }; |
| | | |
| | | // 更新批量操作区域显示状态 |
| | | const updateBatchActionsVisibility = () => { |
| | | showBatchActions.value = selectedItems.value.length > 0; |
| | | }; |
| | | |
| | | // 清空选择 |
| | | const clearSelection = () => { |
| | | selectedItems.value = []; |
| | | isAllSelected.value = false; |
| | | showBatchActions.value = false; |
| | | }; |
| | | |
| | | // 获取选中的项目 |
| | | const getSelectedItems = () => { |
| | | return tableData.value.filter(item => selectedItems.value.includes(item.id)); |
| | | }; |
| | | |
| | | // 自动派单功能 |
| | | const handleAutoDispatch = () => { |
| | | const selectedItemsList = getSelectedItems(); |
| | | |
| | | if (selectedItemsList.length === 0) { |
| | | uni.showToast({ |
| | | title: '请先选择要派工的项目', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // 检查是否有项目待排数量不足 |
| | | const invalidItems = selectedItemsList.filter(item => item.pendingQuantity <= 0); |
| | | if (invalidItems.length > 0) { |
| | | uni.showToast({ |
| | | title: `有${invalidItems.length}个项目无需派工,已自动过滤`, |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | |
| | | // 过滤掉待排数量不足的项目 |
| | | const validItems = selectedItemsList.filter(item => item.pendingQuantity > 0); |
| | | |
| | | if (validItems.length === 0) { |
| | | uni.showToast({ |
| | | title: '没有可派工的项目', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | uni.showModal({ |
| | | title: '确认自动派单', |
| | | content: `确定要对选中的${validItems.length}个项目进行自动派单吗?`, |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | executeAutoDispatch(validItems); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 执行自动派单 |
| | | const executeAutoDispatch = (items) => { |
| | | showLoadingToast('自动派单中...'); |
| | | |
| | | // 模拟自动派单过程 |
| | | setTimeout(() => { |
| | | closeToast(); |
| | | |
| | | // 这里应该调用实际的自动派单API |
| | | // 暂时使用模拟成功 |
| | | uni.showToast({ |
| | | title: `成功为${items.length}个项目完成自动派单`, |
| | | icon: 'success' |
| | | }); |
| | | |
| | | // 清空选择 |
| | | clearSelection(); |
| | | // 刷新列表 |
| | | getList(); |
| | | |
| | | console.log('自动派单项目:', items); |
| | | }, 1500); |
| | | }; |
| | | |
| | | // 页面显示时加载数据 |
| | | onShow(() => { |
| | | // 加载列表数据 |
| | | getList(); |
| | | // 清空选择状态 |
| | | clearSelection(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import '@/styles/sales-common.scss'; |
| | | |
| | | // 生产派工页面样式 |
| | | .production-dispatching { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | position: relative; |
| | | padding: 20rpx; |
| | | } |
| | | |
| | | // 列表项样式 |
| | | // 炒机状态区域 |
| | | .machines-section { |
| | | margin-bottom: 30rpx; |
| | | |
| | | .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | } |
| | | |
| | | .machines-grid { |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | gap: 20rpx; |
| | | } |
| | | |
| | | .machine-card { |
| | | background: #ffffff; |
| | | border-radius: 16rpx; |
| | | padding: 24rpx; |
| | | box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); |
| | | border: 1rpx solid #e9ecef; |
| | | } |
| | | |
| | | .machine-title { |
| | | font-size: 28rpx; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | text-align: center; |
| | | margin-bottom: 20rpx; |
| | | padding-bottom: 16rpx; |
| | | border-bottom: 2rpx solid #3498db; |
| | | } |
| | | |
| | | .machine-metrics { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 16rpx; |
| | | } |
| | | |
| | | .metric-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 8rpx 0; |
| | | } |
| | | |
| | | .metric-label { |
| | | font-size: 24rpx; |
| | | color: #6c757d; |
| | | } |
| | | |
| | | .metric-value { |
| | | font-size: 26rpx; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | } |
| | | |
| | | // 输入框样式 |
| | | .metric-input { |
| | | width: 120rpx; |
| | | text-align: right; |
| | | } |
| | | |
| | | // 保存区域 |
| | | .save-section { |
| | | display: flex; |
| | | justify-content: center; |
| | | margin-top: 30rpx; |
| | | padding-top: 20rpx; |
| | | border-top: 1rpx solid #e9ecef; |
| | | } |
| | | |
| | | .save-btn { |
| | | min-width: 200rpx; |
| | | } |
| | | |
| | | // 搜索区域 |
| | | .search-section { |
| | | background: #ffffff; |
| | | border-radius: 16rpx; |
| | | padding: 24rpx; |
| | | margin-bottom: 30rpx; |
| | | box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .search-form { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20rpx; |
| | | } |
| | | |
| | | .search-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 20rpx; |
| | | } |
| | | |
| | | .search-label { |
| | | font-size: 26rpx; |
| | | color: #606266; |
| | | min-width: 140rpx; |
| | | } |
| | | |
| | | .search-input { |
| | | flex: 1; |
| | | } |
| | | |
| | | .search-buttons { |
| | | display: flex; |
| | | gap: 20rpx; |
| | | justify-content: flex-end; |
| | | margin-top: 10rpx; |
| | | } |
| | | |
| | | .search-btn, .reset-btn { |
| | | min-width: 120rpx; |
| | | } |
| | | |
| | | // 列表样式 |
| | | .ledger-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 24rpx; |
| | | } |
| | | |
| | | .list-item { |
| | | background: #ffffff; |
| | | border-radius: 16rpx; |
| | | overflow: hidden; |
| | | box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .ledger-item { |
| | | .detail-value.highlight { |
| | | padding: 0; |
| | | } |
| | | |
| | | .item-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 24rpx 24rpx 0 24rpx; |
| | | } |
| | | |
| | | .item-left { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 16rpx; |
| | | } |
| | | |
| | | .document-icon { |
| | | width: 48rpx; |
| | | height: 48rpx; |
| | | background: #409eff; |
| | | border-radius: 8rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .item-id { |
| | | font-size: 28rpx; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | |
| | | .entry-date { |
| | | font-size: 24rpx; |
| | | color: #909399; |
| | | } |
| | | |
| | | .item-details { |
| | | padding: 24rpx; |
| | | } |
| | | |
| | | .detail-row { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 12rpx 0; |
| | | border-bottom: 1rpx solid #f5f5f5; |
| | | |
| | | &:last-child { |
| | | border-bottom: none; |
| | | } |
| | | } |
| | | |
| | | .detail-label { |
| | | font-size: 26rpx; |
| | | color: #606266; |
| | | } |
| | | |
| | | .detail-value { |
| | | font-size: 26rpx; |
| | | color: #303133; |
| | | font-weight: 500; |
| | | |
| | | &.highlight { |
| | | color: #ff6b35; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .detail-value.danger { |
| | | &.danger { |
| | | color: #ee0a24; |
| | | font-weight: 600; |
| | | } |
| | | } |
| | | |
| | | .action-buttons { |
| | | padding: 0 24rpx 24rpx 24rpx; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .action-btn { |
| | | min-width: 180rpx; |
| | | } |
| | | |
| | | // 空状态 |
| | | .no-data { |
| | | padding: 100rpx 0; |
| | | text-align: center; |
| | | } |
| | | |
| | | .no-data-text { |
| | | font-size: 28rpx; |
| | | color: #909399; |
| | | margin-top: 20rpx; |
| | | } |
| | | |
| | | // 批量操作区域样式 |
| | | .batch-actions-section { |
| | | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | | border-radius: 16rpx; |
| | | padding: 24rpx; |
| | | margin-bottom: 24rpx; |
| | | box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3); |
| | | color: #ffffff; |
| | | } |
| | | |
| | | .batch-info { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .batch-count { |
| | | font-size: 28rpx; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .batch-buttons { |
| | | display: flex; |
| | | gap: 20rpx; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .batch-btn { |
| | | min-width: 180rpx; |
| | | } |
| | | |
| | | // 全选操作区域样式 |
| | | .select-all-section { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | background: #f8f9fa; |
| | | border-radius: 12rpx; |
| | | padding: 20rpx 24rpx; |
| | | margin-bottom: 20rpx; |
| | | border: 1rpx solid #e9ecef; |
| | | } |
| | | |
| | | .select-all-checkbox { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12rpx; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .select-all-text { |
| | | font-size: 26rpx; |
| | | color: #606266; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .select-all-hint { |
| | | font-size: 22rpx; |
| | | color: #909399; |
| | | } |
| | | |
| | | // 列表项选择样式 |
| | | .ledger-item { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | padding: 0; |
| | | } |
| | | |
| | | .item-checkbox { |
| | | padding: 24rpx 16rpx 0 24rpx; |
| | | cursor: pointer; |
| | | display: flex; |
| | | align-items: center; |
| | | min-height: 48rpx; |
| | | } |
| | | |
| | | .item-content { |
| | | flex: 1; |
| | | padding: 0; |
| | | } |
| | | |
| | | // 点击编辑区域样式 |
| | | .metric-value-container { |
| | | cursor: pointer; |
| | | min-width: 120rpx; |
| | | text-align: right; |
| | | padding: 4rpx 8rpx; |
| | | border-radius: 4rpx; |
| | | transition: all 0.2s ease; |
| | | } |
| | | |
| | | .metric-value-container:hover { |
| | | background-color: #f0f8ff; |
| | | border: 1rpx solid #409eff; |
| | | } |
| | | |
| | | // 适配 uView 组件样式 |
| | | :deep(.up-input) { |
| | | background: transparent; |
| | | } |
| | | </style> |
| | | |
| | | :deep(.up-input__content) { |
| | | background: #f8f9fa; |
| | | } |
| | | </style> |