-
admin
8 天以前 9ee8fbbecf45f58fd2469d9049b7938e363d9a4f
pages/dema/workingHourStatistics/workingHourStatistics.vue
@@ -1,76 +1,619 @@
<template>
  <view class="container">
      <view v-for="(item, index) in list" :key="index" class="card">
        <view class="card-content">
         <view class="item-row">
           <text class="label">项目编码:</text>
           <text class="value">{{ item.code }}</text>
   <view class="container">
      <!-- 搜索区域 -->
      <view class="search-container">
         <view class="search-box">
            <view class="search-item" @click="showProjectCodeSelector">
               <text class="search-label">{{ searchParams.projectCode || '项目编码' }}</text>
               <text class="triangle-down">▼</text>
            </view>
            <view class="search-item" @click="showProjectNameSelector">
               <text class="search-label">{{ searchParams.projectName || '项目名称' }}</text>
               <text class="triangle-down">▼</text>
            </view>
            <!-- 添加重置按钮 -->
            <view class="reset-btn" @click="resetSearch" v-if="searchParams.projectCode || searchParams.projectName">
               <uni-icons type="clear" size="14"></uni-icons>
            </view>
         </view>
         <view class="item-row">
           <text class="label">项目名称:</text>
           <text class="value">{{ item.name }}</text>
         </view>
         <view class="item-row">
           <text class="label">工时:</text>
           <text class="value">{{ item.hours }} 小时</text>
         </view>
        </view>
      </view>
  </view>
      <!-- 项目编码选择弹出层 -->
      <uni-popup
         ref="projectCodePopup"
         type="bottom"
         @change="(e) => onPopupChange('projectCode', e.show)"
      >
         <view class="popup-content">
            <view class="popup-header">
               <text class="popup-title">选择项目编码</text>
               <text class="popup-close" @click="closeProjectCodePopup">×</text>
            </view>
            <!-- 添加搜索框 -->
            <view class="popup-search">
               <uni-easyinput
                  v-model="projectCodeKeyword"
                  placeholder="搜索项目编码"
                  prefixIcon="search"
               />
            </view>
            <scroll-view scroll-y class="popup-list">
               <view v-if="!allProjectCodes.size" class="popup-loading">
                  <uni-load-more status="loading" :content-text="loadingText"></uni-load-more>
               </view>
               <view
                  v-else
                  class="popup-item"
                  v-for="item in filteredProjectCodes"
                  :key="item"
                  @click="selectProjectCode(item)"
               >
                  {{ item }}
               </view>
            </scroll-view>
         </view>
      </uni-popup>
      <!-- 项目名称选择弹出层 -->
      <uni-popup
         ref="projectNamePopup"
         type="bottom"
         @change="(e) => onPopupChange('projectName', e.show)"
      >
         <view class="popup-content">
            <view class="popup-header">
               <text class="popup-title">选择项目名称</text>
               <text class="popup-close" @click="closeProjectNamePopup">×</text>
            </view>
            <!-- 添加搜索框 -->
            <view class="popup-search">
               <uni-easyinput
                  v-model="projectNameKeyword"
                  placeholder="搜索项目名称"
                  prefixIcon="search"
               />
            </view>
            <scroll-view scroll-y class="popup-list">
               <view v-if="!allProjectNames.size" class="popup-loading">
                  <uni-load-more status="loading" :content-text="loadingText"></uni-load-more>
               </view>
               <view
                  v-else
                  class="popup-item"
                  v-for="item in filteredProjectNames"
                  :key="item"
                  @click="selectProjectName(item)"
               >
                  {{ item }}
               </view>
            </scroll-view>
         </view>
      </uni-popup>
      <!-- 表格内容区域 -->
      <view class="table-container">
         <view class="table-header">
            <text class="header-title">工时统计列表</text>
            <text class="total-count">共 {{ total }} 条</text>
         </view>
         <!-- 表格内容 -->
         <view class="table-content" v-if="!loading">
            <view v-for="(item, index) in tableData"
                 :key="index"
                 class="card"
                 @click="handleCardClick(item)"
            >
               <view class="card-content">
                  <view class="item-row">
                     <text class="label">项目编码:</text>
                     <text class="value">{{ item.projectCode }}</text>
                  </view>
                  <view class="item-row">
                     <text class="label">项目名称:</text>
                     <text class="value">{{ item.projectName }}</text>
                  </view>
                  <!-- <view class="item-row">
                     <text class="label">工时:</text>
                     <text class="value highlight">{{ item.workTime }} 小时</text>
                  </view> -->
                  <view class="item-row">
                      <text class="label">工时:</text>
                      <text class="value highlight">{{ Number(item.workTime).toFixed(1) }} 小时</text>
                  </view>
                  <view class="item-row">
                     <text class="label">工种:</text>
                     <text class="value">{{ item.workType }}</text>
                  </view>
                  <view class="item-row">
                     <text class="label">项目阶段:</text>
                     <text class="value">{{ item.projectPhase }}</text>
                  </view>
                  <view class="item-row">
                     <text class="label">报工时间:</text>
                     <text class="value">{{ item.reportTime }}</text>
                  </view>
               </view>
            </view>
         </view>
         <!-- 加载状态 -->
         <view class="loading-container" v-if="loading">
            <uni-load-more status="loading"></uni-load-more>
         </view>
         <!-- 空状态 -->
         <view class="empty-container" v-if="!loading && (!tableData || tableData.length === 0)">
            <image src="/static/empty.png" mode="aspectFit" class="empty-image"></image>
            <text class="empty-text">暂无数据</text>
         </view>
      </view>
   </view>
</template>
<script>
export default {
  data() {
    return {
      list: [
        { code: 'P001', name: '项目A', hours: 10 },
        { code: 'P002', name: '项目B', hours: 15 },
        { code: 'P003', name: '项目C', hours: 8 },
        { code: 'P004', name: '项目D', hours: 20 },
        { code: 'P005', name: '项目E', hours: 12 }
      ]
    };
  }
};
   import { listWorkHourInfoNoPage } from '@/api/dema/workHourInfo.js'
   export default {
      data() {
         return {
               searchParams: {
                  projectCode: '',
                  projectName: '',
                  pageNum: 1,
                  pageSize: 10
               },
               loading: false,
               tableData: [],
               total: 0,
               // 项目编码和名称列表
               projectCodes: [],
               projectNames: [],
               // 搜索关键词
               projectCodeKeyword: '',
               projectNameKeyword: '',
               // 用于存储所有不重复的项目编码和名称
               allProjectCodes: new Set(),
               allProjectNames: new Set(),
               loadingText: {
                  contentdown: '加载中...',
                  contentrefresh: '加载中...',
                  contentnomore: '没有更多数据'
               },
               // 添加弹出层状态控制
               popupStatus: {
                  projectCode: false,
                  projectName: false
               },
               // 添加工种和项目阶段的选项数据
               typeSelect: [
                  { value: '软件', text: "机械设计" },
                  { value: '电气设计', text: "电气设计" },
                  { value: '软件', text: "软件" },
                  { value: '软件', text: "视觉" },
                  { value: '电气调试', text: "电气调试" },
                  { value: '电工', text: "电工" },
                  { value: '钳工', text: "钳工" },
                  { value: '现场经理', text: "现场经理" },
               ],
               phaseSelect: [
                  { value: '场内设计', text: "场内设计" },
                  { value: '场内装配', text: "场内装配" },
                  { value: '场内调试', text: "场内调试" },
                  { value: '场外装配', text: "场外装配" },
                  { value: '场外调试', text: "场外调试" },
                  { value: '试生产', text: "试生产" },
                  { value: '陪产', text: "陪产" },
                  { value: '终验收', text: "终验收" },
               ],
         }
      },
      computed: {
         // 过滤后的项目编码列表
         filteredProjectCodes() {
            if (!this.projectCodeKeyword) return Array.from(this.allProjectCodes);
            return Array.from(this.allProjectCodes).filter(code =>
               code.toLowerCase().includes(this.projectCodeKeyword.toLowerCase())
            );
         },
         // 过滤后的项目名称列表
         filteredProjectNames() {
            if (!this.projectNameKeyword) return Array.from(this.allProjectNames);
            return Array.from(this.allProjectNames).filter(name =>
               name.toLowerCase().includes(this.projectNameKeyword.toLowerCase())
            );
         }
      },
      methods: {
         // 修改显示项目编码选择器的方法
         showProjectCodeSelector() {
            if (this.popupStatus.projectCode) {
               // 如果当前是打开状态,则关闭
               this.closeProjectCodePopup();
            } else {
               // 如果当前是关闭状态,则打开(同时关闭另一个)
               this.closeProjectNamePopup(); // 关闭项目名称选择器
               this.$refs.projectCodePopup.open();
               this.popupStatus.projectCode = true;
            }
         },
         // 修改显示项目名称选择器的方法
         showProjectNameSelector() {
            if (this.popupStatus.projectName) {
               // 如果当前是打开状态,则关闭
               this.closeProjectNamePopup();
            } else {
               // 如果当前是关闭状态,则打开(同时关闭另一个)
               this.closeProjectCodePopup(); // 关闭项目编码选择器
               this.$refs.projectNamePopup.open();
               this.popupStatus.projectName = true;
            }
         },
         // 修改关闭方法
         closeProjectCodePopup() {
            this.$refs.projectCodePopup.close();
            this.projectCodeKeyword = '';
            this.popupStatus.projectCode = false;
         },
         closeProjectNamePopup() {
            this.$refs.projectNamePopup.close();
            this.projectNameKeyword = '';
            this.popupStatus.projectName = false;
         },
         // 选择项目编码
         selectProjectCode(code) {
            this.searchParams.projectCode = code
            this.closeProjectCodePopup()
            this.getList()
         },
         // 选择项目名称
         selectProjectName(name) {
            this.searchParams.projectName = name
            this.closeProjectNamePopup()
            this.getList()
         },
         // 获取列表数据
         getList() {
            this.loading = true
            this.tableData = [] // 清空现有数据
            listWorkHourInfoNoPage(this.searchParams).then(response => {
               this.tableData = response.rows || []
               this.total = response.total || 0
               // 更新项目编码和名称集合
               this.tableData.forEach(item => {
                  if (item.projectCode) this.allProjectCodes.add(item.projectCode);
                  if (item.projectName) this.allProjectNames.add(item.projectName);
               });
               this.loading = false
            }).catch(() => {
               this.loading = false
               this.$modal.msgError('获取数据失败')
            })
         },
         // 初始化
         async init() {
            try {
               // 先获取所有项目数据用于检索
               await this.getAllProjects();
               // 然后获取当前页的数据
               await this.getList();
            } catch (error) {
               console.error('初始化失败:', error);
            }
         },
         // 重置搜索
         resetSearch() {
            this.searchParams.projectCode = ''
            this.searchParams.projectName = ''
            this.projectCodeKeyword = ''
            this.projectNameKeyword = ''
            this.getList()
         },
         // 获取所有项目数据
         async getAllProjects() {
            try {
               this.loading = true;
               const response = await listWorkHourInfoNoPage({
                  pageNum: 1,
                  pageSize: 999 // 获取足够多的数据以获取所有不重复的项目
               });
               if (response && response.rows) {
                  // 清空现有集合
                  this.allProjectCodes.clear();
                  this.allProjectNames.clear();
                  // 添加新数据
                  response.rows.forEach(item => {
                     if (item.projectCode) this.allProjectCodes.add(item.projectCode);
                     if (item.projectName) this.allProjectNames.add(item.projectName);
                  });
               }
               this.loading = false;
            } catch (error) {
               console.error('获取项目列表失败:', error);
               this.loading = false;
               this.$modal.msgError('获取项目列表失败');
            }
         },
         // 添加弹出层状态监听
         onPopupChange(type, show) {
            this.popupStatus[type] = show;
         },
         // 修改卡片点击处理方法
         handleCardClick(item) {
            // 检查是否是当天的记录
            const today = new Date().toISOString().split('T')[0]; // 获取当前日期 YYYY-MM-DD
            const reportDate = item.reportTime.split(' ')[0]; // 获取报工日期部分 YYYY-MM-DD
            if (reportDate === today) {
               // 是当天的记录,允许编辑
               const params = {
                  workHourId: item.workHourId,
                  projectCode: item.projectCode,
                  projectName: item.projectName,
                  projectPhase: item.projectPhase,
                  workType: item.workType,
                  workTime: item.workTime,
                  details: item.details,
                  isEdit: true
               };
               uni.navigateTo({
                  url: '/pages/dema/workHour/workHour?' + this.parseParams(params)
               });
            } else {
               // 不是当天的记录,显示警告
               this.$modal.msgError("只能修改当天的工时记录!");
            }
         },
         // 添加参数解析方法
         parseParams(params) {
            return Object.keys(params)
               .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
               .join('&');
         },
         // 获取工种文本
         getWorkTypeText(value) {
            const item = this.typeSelect.find(item => item.value === value);
            return item ? item.text : value;
         },
         // 获取项目阶段文本
         getPhaseText(value) {
            const item = this.phaseSelect.find(item => item.value === value);
            return item ? item.text : value;
         },
         // 添加日期格式化辅助方法
         formatDate(date) {
            const d = new Date(date);
            const year = d.getFullYear();
            const month = String(d.getMonth() + 1).padStart(2, '0');
            const day = String(d.getDate()).padStart(2, '0');
            return `${year}-${month}-${day}`;
         }
      },
      async created() {
         // 在组件创建时就开始初始化
         await this.init();
      },
      mounted() {
         // 如果需要其他初始化操作,放在这里
      }
   }
</script>
<style>
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 10px;
}
   .container {
      display: flex;
      flex-direction: column;
      width: 100%;
   }
.card {
  width: 100%;
  background-color: #f9f9f9;
  border: 1px solid #ddd;
  border-radius: 8px;
  margin-bottom: 20px;
  padding: 20px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
   .search-container {
      position: sticky;
      top: 0;
      z-index: 100;
      background-color: #fff;
      padding: 12px 0;
      border-bottom: 1px solid #eee;
      box-shadow: 0 2px 4px rgba(0,0,0,0.05);
   }
.card-content {
  display: flex;
  flex-direction: column;
}
   .search-box {
      position: relative;
      display: flex;
      justify-content: center;
      align-items: center;
      gap: 15px;
   }
.item-row {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
   .search-item {
      min-width: 120px;
      padding: 8px 15px;
      background-color: #f5f7fa;
      border-radius: 4px;
      transition: all 0.3s;
   }
.label {
  font-size: 16px;
  text-align: left;
}
   .search-item:hover {
      background-color: #e8f4ff;
   }
.value {
  font-size: 16px;
  text-align: right;
}
   .search-label {
      color: #333;
      font-size: 14px;
   }
   .triangle-down {
      margin-left: 5px;
      color: #909399;
   }
   .reset-btn {
      position: absolute;
      right: 20px;
      padding: 5px;
      cursor: pointer;
   }
   .popup-content {
      background-color: #fff;
      border-radius: 16px 16px 0 0;
      padding: 20px;
   }
   .popup-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding-bottom: 10px;
      border-bottom: 1px solid #eee;
   }
   .popup-title {
      font-size: 16px;
      font-weight: bold;
   }
   .popup-close {
      font-size: 20px;
      color: #666;
      padding: 0 10px;
      cursor: pointer;
   }
   .popup-search {
      padding: 10px 0;
      border-bottom: 1px solid #ebeef5;
   }
   .popup-list {
      margin-top: 10px;
      max-height: 40vh;
   }
   .popup-item {
      padding: 12px 15px;
      border-bottom: 1px solid #ebeef5;
      transition: all 0.3s;
   }
   .popup-item:hover {
      background-color: #f5f7fa;
   }
   .popup-item:active {
      background-color: #e8f4ff;
   }
   .table-container {
      flex: 1;
      padding: 15px;
      background-color: #f5f7fa;
   }
   .table-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 15px;
      padding: 0 10px;
   }
   .header-title {
      font-size: 16px;
      font-weight: bold;
      color: #333;
   }
   .total-count {
      font-size: 14px;
      color: #909399;
   }
   .table-content {
      display: flex;
      flex-direction: column;
      gap: 12px;
   }
   .card {
      background-color: #fff;
      border-radius: 8px;
      padding: 15px;
      box-shadow: 0 2px 12px 0 rgba(0,0,0,0.05);
      transition: all 0.3s;
   }
   .card:hover {
      transform: translateY(-2px);
      box-shadow: 0 4px 12px 0 rgba(0,0,0,0.1);
   }
   .item-row {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 8px 0;
      border-bottom: 1px solid #ebeef5;
   }
   .item-row:last-child {
      border-bottom: none;
   }
   .label {
      color: #606266;
      font-size: 14px;
   }
   .value {
      color: #333;
      font-size: 14px;
   }
   .highlight {
      color: #409eff;
      font-weight: bold;
   }
   .loading-container {
      padding: 20px 0;
      display: flex;
      justify-content: center;
   }
   .empty-container {
      padding: 40px 0;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
   }
   .empty-image {
      width: 120px;
      height: 120px;
      margin-bottom: 15px;
   }
   .empty-text {
      color: #909399;
      font-size: 14px;
   }
   .popup-loading {
      padding: 20px 0;
      display: flex;
      justify-content: center;
      align-items: center;
   }
</style>