<template>
|
<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>
|
|
<!-- 项目编码选择弹出层 -->
|
<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>
|
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;
|
width: 100%;
|
}
|
|
.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);
|
}
|
|
.search-box {
|
position: relative;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
gap: 15px;
|
}
|
|
.search-item {
|
min-width: 120px;
|
padding: 8px 15px;
|
background-color: #f5f7fa;
|
border-radius: 4px;
|
transition: all 0.3s;
|
}
|
|
.search-item:hover {
|
background-color: #e8f4ff;
|
}
|
|
.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>
|