页面完善

This commit is contained in:
BianLzhaoMin 2025-09-17 17:21:46 +08:00
parent b6dd7cd59f
commit a27bd10842
16 changed files with 2548 additions and 0 deletions

View File

@ -0,0 +1,10 @@
import request from '@/utils/request'
// 综合查询 获取三表一册列表
export const getThreeAndOneListAPI = (data) => {
return request({
url: '/bmw/workerLight/xxx',
method: 'GET',
params: data,
})
}

View File

@ -0,0 +1,10 @@
import request from '@/utils/request'
// 综合查询 获取工资统计列表
export const getWageCountListAPI = (data) => {
return request({
url: '/bmw/workerLight/****',
method: 'GET',
params: data,
})
}

View File

@ -10,6 +10,7 @@
v-show="showSearch"
:model="queryParams"
label-width="auto"
class="query-form"
>
<el-form-item
:key="v"
@ -114,6 +115,8 @@
<slot name="btn" :queryParams="queryParams"></slot>
</el-form-item>
<slot name="left-tip"> </slot>
</el-form>
<!-- 按钮集群 -->
<el-row class="btn-container">
@ -595,4 +598,8 @@ export default {
padding: 6px 12px;
}
}
.query-form {
position: relative;
}
</style>

View File

@ -115,6 +115,34 @@ export const constantRoutes = [
activeMenu: '/synthesize-query/person-count',
},
},
// 三表一册详情页面
{
path: 'three-and-one-detail',
name: 'ThreeAndOneDetail',
hidden: true,
component: () =>
import(
'@/views/synthesize-query/three-and-one/detail/index.vue'
),
meta: {
title: '三表一册详情',
activeMenu: '/synthesize-query/three-and-one',
},
},
// 三表一册月份详情页面
{
path: 'three-and-one-month-detail',
name: 'ThreeAndOneMonthDetail',
hidden: true,
component: () =>
import(
'@/views/synthesize-query/three-and-one/month-detail/index.vue'
),
meta: {
title: '月份详情',
activeMenu: '/synthesize-query/three-and-one',
},
},
],
},
{

View File

@ -0,0 +1,29 @@
export const formLabel = [
{
isShow: false, // 是否展示label
f_type: 'ipt',
f_label: '工程名称',
f_model: 'proName',
},
{
isShow: false, // 是否展示label
f_type: 'sel',
f_label: '工程状态',
f_model: 'proStatus',
},
]
export const columnsList = [
{ t_props: 'mainProName', t_label: '分公司' },
{ t_label: '工程名称', t_props: 'volLevel' },
{
t_label: '发放月份数量',
t_props: 'volLevel',
},
{ t_slot: 'proStatus', t_label: '发放分包数量' },
{ t_slot: 'proStatus', t_label: '发放班组数量' },
{ t_slot: 'proStatus', t_label: '发放人员人次' },
{ t_slot: 'proStatus', t_label: '实发工资' },
{ t_slot: 'proStatus', t_label: '状态' },
]

View File

@ -0,0 +1,281 @@
<template>
<!-- 头部工程详情信息 -->
<div class="header-info">
<el-card class="project-info-card">
<div class="project-header">
<!-- 项目图标区域 -->
<div class="project-icon">
<div class="icon-placeholder">
<!-- 图标占位符后续可替换为实际图标 -->
<i class="el-icon-setting"></i>
</div>
</div>
<!-- 项目信息区域 -->
<div class="project-details">
<div class="project-title">
{{ projectInfo.projectName }}
</div>
<div class="company-name">
{{ projectInfo.companyName }}
</div>
</div>
<div class="left-tip">
1. 每月1号0点自动生成上月"三表一册"
<br />
2. 请在每月5号24点前完成数据确认完成后请进行数据封档
<br />
3. 未封档数据系统在5号24点后自动封档
<br />
4. 封档后无法进行补卡支付表操作等
</div>
</div>
<!-- 项目属性信息 -->
<div class="project-attributes">
<div class="attribute-row">
<div
class="attribute-item"
v-for="item in labelList"
:key="item.valueKey"
>
<span class="attribute-label">{{ item.label }}</span>
<span
class="attribute-value"
:class="{
'status-active':
item.valueKey === 'currentStatus',
}"
>
<span class="status-dot"></span>
{{ projectInfo[item.valueKey] }}
</span>
</div>
</div>
</div>
</el-card>
</div>
</template>
<script>
export default {
name: 'HeaderInfo',
data() {
return {
projectInfo: {
projectName: '220kV永和(云纺)输变电工程(变电部分)',
companyName: '输电一公司',
currentStatus: '在建',
projectType: '基建线路',
voltageLevel: '220kV',
plannedStartDate: '2025-02-01',
plannedCompletionDate: '2025-11-30',
projectLocation:
'广东省-东莞市广东省-东莞市广东省-东莞市广东省-东莞市广东省-东莞市广东省-东莞市',
},
labelList: [
{
label: '当前状态',
value: '在建',
valueKey: 'currentStatus',
},
{
label: '工程类型',
value: '基建线路',
valueKey: 'projectType',
},
{
label: '电压等级',
value: '220kV',
valueKey: 'voltageLevel',
},
{
label: '计划开工时间',
value: '2025-02-01',
valueKey: 'plannedStartDate',
},
{
label: '计划完工时间',
value: '2025-11-30',
valueKey: 'plannedCompletionDate',
},
{
label: '工程地址',
value: '广东省-东莞市',
valueKey: 'projectLocation',
},
],
}
},
}
</script>
<style lang="scss" scoped>
@import '@/assets/styles/variables.scss';
.header-info {
margin-bottom: 20px;
.project-info-card {
border-radius: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border: none;
position: relative;
::v-deep .el-card__body {
padding: 24px;
}
}
.project-header {
display: flex;
align-items: flex-start;
margin-bottom: 24px;
.project-icon {
margin-right: 20px;
flex-shrink: 0;
.icon-placeholder {
width: 60px;
height: 60px;
background: linear-gradient(135deg, #fce7f3 0%, #f3e8ff 100%);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(236, 72, 153, 0.2);
i {
font-size: 28px;
color: #ec4899;
}
}
}
.project-details {
flex: 1;
.project-title {
font-size: 20px;
font-weight: bold;
color: #1f2937;
margin-bottom: 8px;
line-height: 1.4;
}
.company-name {
font-size: 14px;
color: #6b7280;
font-weight: 500;
}
}
}
.project-attributes {
margin-left: 80px; //
.attribute-row {
display: flex;
gap: 70px;
flex-wrap: wrap;
.attribute-item {
// flex: 1;
// min-width: 120px;
display: flex;
flex-direction: column;
align-items: flex-start; //
text-align: left; //
.attribute-label {
font-size: 12px;
color: #9ca3af;
margin-bottom: 16px;
font-weight: 500;
}
.attribute-value {
font-size: 14px;
color: #374151;
font-weight: 500;
word-break: break-all;
&.status-active {
display: flex;
align-items: center;
justify-content: flex-start; //
.status-dot {
width: 8px;
height: 8px;
background-color: $green;
border-radius: 50%;
margin-right: 6px;
display: inline-block;
}
}
}
}
}
}
.left-tip {
position: absolute;
top: 5%;
right: 1%;
font-size: 13px;
line-height: 1.5;
color: #ef4444;
}
}
//
@media (max-width: 1200px) {
.header-info {
.project-attributes {
margin-left: 80px; //
.attribute-row {
.attribute-item {
min-width: 100px;
}
}
}
}
}
@media (max-width: 768px) {
.header-info {
.project-header {
flex-direction: column;
align-items: center;
text-align: center;
.project-icon {
margin-right: 0;
margin-bottom: 16px;
}
}
.project-attributes {
margin-left: 0; //
text-align: center;
.attribute-row {
flex-direction: column;
gap: 12px;
.attribute-item {
min-width: auto;
width: 100%;
align-items: center; //
text-align: center;
}
}
}
}
}
</style>

View File

@ -0,0 +1,379 @@
<template>
<!-- 三表一册表格 -->
<div class="sub-team-card-container">
<div class="section-header">
<span>"三表一册"</span>
</div>
<div class="section-content">
<!-- 分包信息表格 -->
<div class="section-container" id="subcontractor-table">
<div class="section-header">
<div class="section-title">
<div class="title-indicator"></div>
<span>每月数据</span>
</div>
</div>
<div class="table-container">
<el-table
stripe
border
style="width: 100%"
:data="threeOneData"
:cell-style="tableCellStyle"
:header-cell-style="tableHeaderStyle"
>
<el-table-column
align="center"
:key="item.prop"
:prop="item.prop"
:label="item.label"
show-overflow-tooltip
v-for="item in columnsList"
/>
<el-table-column align="center" label="操作">
<template slot-scope="scope">
<el-button
type="text"
@click="onHandleOpenDetail(scope.row)"
>
详情
</el-button>
<el-button
type="text"
@click="onHandleDownloadFile(scope.row)"
>
下载
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</template>
<script>
import DialogModel from '@/components/DialogModel/index.vue'
export default {
name: 'SubTeamCard',
components: {
DialogModel,
},
data() {
return {
//
threeOneData: [
{
month: '3月',
},
{
month: '5月',
},
],
columnsList: [
{
label: '月份',
prop: 'month',
},
{
label: '花名册',
prop: 'nameList',
},
{
label: '考勤明细表',
prop: 'month',
},
{
label: '工资信息报审表',
prop: 'month',
},
{
label: '工资支付表',
prop: 'month',
},
{
label: '状态',
prop: 'month',
},
{
label: '封档时间',
prop: 'month',
},
{
label: '回单上传状态',
prop: 'month',
},
{
label: '上传时间',
prop: 'month',
},
],
dialogConfig: {
outerTitle: '授权委托书',
outerWidth: '80%',
outerVisible: false,
minHeight: '90vh',
maxHeight: '90vh',
},
}
},
methods: {
//
tableHeaderStyle() {
return {
backgroundColor: '#f5f7fa',
color: '#606266',
fontWeight: '500',
fontSize: '14px',
textAlign: 'center',
}
},
//
tableCellStyle() {
return {
fontSize: '14px',
color: '#606266',
padding: '12px 8px',
}
},
//
onHandleOpenPreviewFile(row, type) {
console.log('row', row)
switch (type) {
case 1:
this.dialogConfig.outerTitle = '授权委托书'
break
case 2:
this.dialogConfig.outerTitle = '工资已支付完成承诺书'
break
case 3:
this.dialogConfig.outerTitle = '施工班组承诺书'
break
}
this.dialogConfig.outerVisible = true
},
//
handleCloseDialogOuter() {
this.dialogConfig.outerVisible = false
},
//
onHandleOpenDetail(row) {
console.log('row', row)
this.$router.push({
name: 'ThreeAndOneMonthDetail',
})
},
//
onHandleDownloadFile(row) {
console.log('row', row)
},
},
}
</script>
<style lang="scss" scoped>
@import '@/assets/styles/variables.scss';
.sub-team-card-container {
margin-bottom: 20px;
padding-bottom: 20px;
border-radius: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
background-color: #fff;
border: 1px solid #f0f0f0;
.section-header {
padding: 16px 10px;
font-size: 18px;
font-weight: 600;
color: #000;
font-family: 'PingFang SC';
background-color: #f5f7fa;
border-bottom: 1px solid #f0f0f0;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
}
.section-content {
padding: 0 20px;
}
.section-container {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
margin-top: 20px;
overflow: hidden;
.section-header {
padding: 20px 24px 16px;
border-bottom: 1px solid #f0f0f0;
.section-title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 600;
color: #1f2937;
.title-indicator {
width: 4px;
height: 20px;
background: #3b82f6;
border-radius: 2px;
margin-right: 12px;
}
}
}
.table-container {
padding: 0;
::v-deep .el-table {
border: none;
.el-table__header-wrapper {
.el-table__header {
th {
border-bottom: 1px solid #e4e7ed;
border-right: 1px solid #e4e7ed;
&:last-child {
border-right: none;
}
}
}
}
.el-table__body-wrapper {
.el-table__body {
tr {
&:hover {
background-color: #f8f9fa;
}
td {
border-bottom: 1px solid #f0f0f0;
border-right: 1px solid #f0f0f0;
&:last-child {
border-right: none;
}
}
}
}
}
}
}
}
.status-cell {
display: flex;
align-items: center;
justify-content: center;
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 6px;
display: inline-block;
&.status-online {
background-color: #10b981;
}
&.status-offline {
background-color: #ef4444;
}
}
}
.upload-status {
font-size: 14px;
font-weight: 500;
cursor: pointer;
&.uploaded {
color: #10b981;
}
&.not-uploaded {
color: #9ca3af;
}
}
}
//
@media (max-width: 1200px) {
.sub-team-card-container {
.section-container {
.table-container {
::v-deep .el-table {
font-size: 13px;
}
}
}
}
}
@media (max-width: 768px) {
.sub-team-card-container {
.section-container {
.section-header {
padding: 16px 20px 12px;
.section-title {
font-size: 15px;
}
}
.table-container {
::v-deep .el-table {
font-size: 12px;
.el-table__header-wrapper {
.el-table__header {
th {
padding: 8px 4px;
font-size: 12px;
}
}
}
.el-table__body-wrapper {
.el-table__body {
td {
padding: 8px 4px;
}
}
}
}
}
}
.status-cell {
.status-dot {
width: 6px;
height: 6px;
margin-right: 4px;
}
}
.upload-status {
font-size: 12px;
cursor: pointer;
}
}
}
</style>

View File

@ -0,0 +1,63 @@
<template>
<!-- 综合查询 ---- 工程统计详情 -->
<div class="app-container">
<HeaderInfo />
<ThreeOneTable />
</div>
</template>
<script>
import HeaderInfo from './components/header-info.vue'
import ThreeOneTable from './components/three-one-table.vue'
export default {
name: 'ProjectCountDetail',
components: {
HeaderInfo,
ThreeOneTable,
},
data() {
return {
projectId: null, // ID
}
},
created() {
// ID
this.projectId = this.$route.params.id || this.$route.query.id
},
methods: {
//
handleCardClick(card) {
this.scrollToTarget(card.type)
// const attMachineCard_1 = document.getElementById('attMachineCard_1')
},
//
scrollToTarget(cardType) {
const cardTypeMap = {
subcontractor: 'subcontractor-table', // ->
team: 'team-table', // ->
entry: 'entry-exit-info', // ->
onsite: 'entry-exit-info', // ->
attendance: 'attendance-info', // ->
wage: 'salary-info', // ->
machine: 'attMachine-table', // ->
}
const targetElement = document.getElementById(cardTypeMap[cardType])
// 使 nextTick DOM
this.$nextTick(() => {
if (!targetElement) {
return
}
targetElement.scrollIntoView({
behavior: 'smooth',
block: 'start',
inline: 'nearest',
})
})
},
},
}
</script>

View File

@ -0,0 +1,94 @@
<template>
<!-- 综合查询 ---- 三表一册-->
<div class="app-container">
<TableModel
:formLabel="formLabel"
:showOperation="true"
:showRightTools="true"
ref="threeAndOneTableRef"
:columnsList="columnsList"
:testTableList="testTableList"
:request-api="getThreeAndOneListAPI"
>
<template slot="handle" slot-scope="{ queryParams }">
<el-button
plain
size="mini"
type="primary"
icon="el-icon-view"
@click="onHandleViewDetail(queryParams)"
>
详情
</el-button>
</template>
<template slot="left-tip">
<div class="left-tip">
1. 每月1号0点自动生成上月"三表一册"
<br />
2. 请在每月5号24点前完成数据确认完成后请进行数据封档
<br />
3. 未封档数据系统在5号24点后自动封档
<br />
4. 封档后无法进行补卡支付表操作等
</div>
</template>
</TableModel>
</div>
</template>
<script>
import TableModel from '@/components/TableModel'
import { formLabel, columnsList } from './config'
import { getThreeAndOneListAPI } from '@/api/synthesize-query/three-and-one'
export default {
name: 'ThreeAndOne',
components: {
TableModel,
},
data() {
return {
formLabel,
columnsList,
getThreeAndOneListAPI,
testTableList: [
{
mainProName: '分公司1',
volLevel: '工程1',
subNum: 1,
teamNum: 1,
teamNum: 1,
},
{
mainProName: '分公司1',
volLevel: '工程1',
subNum: 1,
teamNum: 1,
teamNum: 1,
},
],
}
},
methods: {
onHandleViewDetail(queryParams) {
console.log(queryParams)
this.$router.push({
name: 'ThreeAndOneDetail',
})
},
},
}
</script>
<style lang="scss" scoped>
.left-tip {
position: absolute;
top: 0;
right: 5%;
font-size: 13px;
line-height: 1.5;
color: #ef4444;
}
</style>

View File

@ -0,0 +1,277 @@
<template>
<!-- 考勤明细 -->
<div class="section-container">
<div class="table-container">
<el-form
:inline="true"
label-width="auto"
:model="nameListQueryParams"
style="margin-top: 20px; padding-left: 20px; display: flex"
>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入分包"
/>
</el-form-item>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入姓名"
/>
</el-form-item>
<el-form-item>
<el-button
size="mini"
type="primary"
icon="el-icon-search"
@click="handleQuery"
>
查询
</el-button>
<el-button
plain
size="mini"
type="warning"
icon="el-icon-refresh"
@click="resetQuery"
>
重置
</el-button>
<el-button
plain
size="mini"
type="success"
icon="el-icon-download"
@click="handleExport"
>
导出
</el-button>
</el-form-item>
<el-form-item
style="flex: 1; text-align: right; color: #ef4444"
>
<span>出勤1</span>
<span>缺勤1</span>
<span>无对应日期1</span>
</el-form-item>
</el-form>
<el-table
border
stripe
style="width: 100%"
:data="nameListData"
:header-cell-style="tableHeaderStyle"
:cell-style="tableCellStyle"
>
<el-table-column
align="center"
:key="item.prop"
:prop="item.prop"
:label="item.label"
show-overflow-tooltip
fixed="left"
v-for="item in columnData"
/>
<el-table-column label="出勤统计">
<el-table-column
align="center"
:key="j"
:label="j"
width="50"
v-for="j in 30"
/>
</el-table-column>
<el-table-column
align="center"
label="出勤天数"
fixed="right"
/>
<el-table-column align="center" label="签字" fixed="right" />
<el-table-column
align="center"
label="其他备注"
fixed="right"
/>
</el-table>
<!-- <div style="padding-right: 20px">
<pagination
:total="total"
@pagination="getNameListData"
:page.sync="nameListQueryParams.pageNum"
:limit.sync="nameListQueryParams.pageSize"
/>
</div> -->
</div>
</div>
</template>
<script>
export default {
name: 'WageInfo',
props: {},
data() {
return {
total: 100,
nameListQueryParams: {
entryTime: '',
pageNum: 1,
pageSize: 10,
},
nameListData: [
{
entryTime: '测试',
},
{
entryTime: '测试',
},
],
columnData: [
{
label: '项目名称',
prop: 'entryTime',
},
{
label: '分包队伍全称',
prop: 'exitTime',
},
{
label: '姓名',
prop: 'subcontractorName',
},
{
label: '身份证号',
prop: 'totalEntryCount',
},
{
label: '职务/工种',
prop: 'totalEntryCount',
},
],
}
},
created() {},
watch: {},
methods: {
//
tableHeaderStyle() {
return {
backgroundColor: '#f5f7fa',
color: '#606266',
fontWeight: '500',
fontSize: '14px',
textAlign: 'center',
}
},
//
tableCellStyle() {
return {
fontSize: '14px',
color: '#606266',
padding: '12px 8px',
}
},
//
handleQuery() {
// this.getAttInfoData()
},
//
resetQuery() {
this.attInfoQueryParams = {
entryTime: '',
}
},
//
handleExport() {
// this.download(
// '/bmw/workerLight/attExportByWorker',
// {
// ...this.attInfoQueryParams,
// },
// '.xlsx',
// )
},
//
getNameListData() {
// this.getAttInfoData()
},
},
}
</script>
<style lang="scss" scoped>
@import '@/assets/styles/variables.scss';
.section-container {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
overflow: hidden;
// padding: 20px 0;
.section-header {
padding: 20px 24px 16px;
border-bottom: 1px solid #f0f0f0;
.section-title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 600;
color: #1f2937;
.title-indicator {
width: 4px;
height: 20px;
background: #3b82f6;
border-radius: 2px;
margin-right: 12px;
}
}
}
.table-container {
padding: 0;
::v-deep .el-table {
border: none;
.el-table__header-wrapper {
.el-table__header {
th {
border-bottom: 1px solid #e4e7ed;
border-right: 1px solid #e4e7ed;
&:last-child {
border-right: none;
}
}
}
}
.el-table__body-wrapper {
.el-table__body {
tr {
&:hover {
background-color: #f8f9fa;
}
td {
border-bottom: 1px solid #f0f0f0;
border-right: 1px solid #f0f0f0;
&:last-child {
border-right: none;
}
}
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,326 @@
<template>
<!-- 头部工程详情信息 -->
<div class="header-info">
<el-card class="project-info-card">
<div class="project-header">
<!-- 项目信息区域 -->
<div class="project-details">
<div class="project-title"> 月份2025-09 </div>
</div>
<div>
<el-button size="mini" type="danger" @click="onHandlePack">
封档
</el-button>
<el-button
size="mini"
type="success"
@click="onHandleUpload"
>
回单上传
</el-button>
<el-button size="mini" plain @click="onHandleDownload">
下载三表一册
</el-button>
</div>
</div>
<div class="label-list">
<div class="left">
<div
class="label-item"
:key="item.label"
v-for="item in labelList"
>
<span class="label-label">{{ item.label }}</span>
<span class="label-value">{{ item.value }}</span>
</div>
</div>
<div class="right"> 待封档 </div>
</div>
</el-card>
<el-dialog
width="40%"
append-to-body
title="银行回单上传"
:visible.sync="uploadVisible"
>
<el-upload
action="#"
multiple
limit="1"
class="upload-demo"
:file-list="fileList"
:auto-upload="false"
:on-remove="handleRemove"
:on-change="handleChange"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text"
>将文件拖到此处<em>点击上传</em></div
>
</el-upload>
<el-row class="dialog-footer-btn">
<el-button size="medium" @click="onHandleCancel">
取消
</el-button>
<el-button
size="medium"
type="primary"
@click="onHandleConfirm"
>
确定
</el-button>
</el-row>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'HeaderInfo',
data() {
return {
uploadVisible: false,
fileSize: 10,
fileList: [],
labelList: [
{
label: '分包数量',
value: '1',
},
{
label: '人员数量',
value: '128',
},
{
label: '封档人',
value: '李思思',
},
{
label: '封档时间',
value: '2025-09-01',
},
{
label: '回单附件',
value: '2',
},
{
label: '班组数量',
value: '6',
},
{
label: '实发工资',
value: '10000',
},
{
label: '回单上传人',
value: '李思思',
},
{
label: '回单上传时间',
value: '2025-09-01',
},
],
}
},
methods: {
onHandlePack() {
console.log('封档')
this.$modal
.confirm('是否确定封档?')
.then(() => {
console.log('封档')
})
.catch(() => {
console.log('取消')
})
},
onHandleUpload() {
console.log('回单上传')
this.uploadVisible = true
this.fileList = []
},
onHandleDownload() {
console.log('下载三表一册')
},
onHandleCancel() {
this.uploadVisible = false
this.fileList = []
},
onHandleConfirm() {
this.uploadVisible = false
},
//
handleChange(file, fileList) {
// const isFormat = this.fileType.some((e) => file.name.endsWith(e))
// if (!isFormat) {
// this.$modal.msgError(
// `, ${this.fileType.join(
// '',
// )}!`,
// )
// this.$emit(
// 'update:fileList',
// fileList.filter((item) => item.uid !== file.uid),
// )
// return false
// }
//
const isLt = file.size / 1024 / 1024 < this.fileSize
if (!isLt) {
this.$modal.msgError(`图片大小不能超过 ${this.fileSize} MB`)
this.$emit(
'update:fileList',
fileList.filter((item) => item.uid !== file.uid),
)
return false
}
//
if (file.name.length > 40) {
this.$modal.msgError('文件名称不能超过40个字符')
this.$emit(
'update:fileList',
fileList.filter((item) => item.uid !== file.uid),
)
return false
}
this.fileList = fileList
},
//
handleRemove(file, fileList) {
this.fileList = fileList
},
},
}
</script>
<style lang="scss" scoped>
@import '@/assets/styles/variables.scss';
.header-info {
margin-bottom: 20px;
.project-info-card {
border-radius: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border: none;
::v-deep .el-card__body {
padding: 24px;
}
}
.project-header {
display: flex;
align-items: flex-start;
margin-bottom: 24px;
.project-icon {
margin-right: 20px;
flex-shrink: 0;
.icon-placeholder {
width: 60px;
height: 60px;
background: linear-gradient(135deg, #fce7f3 0%, #f3e8ff 100%);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(236, 72, 153, 0.2);
i {
font-size: 28px;
color: #ec4899;
}
}
}
.project-details {
flex: 1;
.project-title {
font-size: 20px;
font-weight: bold;
color: #1f2937;
margin-bottom: 8px;
line-height: 1.4;
}
.company-name {
font-size: 14px;
color: #6b7280;
font-weight: 500;
}
}
}
.label-list {
display: flex;
align-items: center;
justify-content: space-between;
.left {
width: 80%;
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 6;
.label-item {
padding: 16px 0;
transition: background-color 0.3s ease;
}
.label-label {
font-size: 14px;
color: #6b7280;
margin-bottom: 8px;
font-weight: 500;
min-width: 120px;
text-align: right;
display: inline-block;
}
.label-value {
font-size: 13px;
color: #1f2937;
}
}
.right {
width: 20%;
}
}
}
.upload-demo {
width: 100%;
height: 200px;
border: 1px dashed #d9d9d9;
display: flex;
align-items: center;
justify-content: center;
color: $blue;
.el-upload__text {
font-size: 16px;
}
.el-icon-upload {
font-size: 28px;
}
em {
font-style: normal;
}
}
</style>

View File

@ -0,0 +1,307 @@
<template>
<!-- 花名册 -->
<div class="section-container">
<div class="table-container">
<el-form
:inline="true"
label-width="auto"
:model="nameListQueryParams"
style="margin-top: 20px; padding-left: 20px"
>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入分包"
/>
</el-form-item>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入班组"
/>
</el-form-item>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入姓名"
/>
</el-form-item>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入在岗情况"
/>
</el-form-item>
<el-form-item>
<el-button
size="mini"
type="primary"
icon="el-icon-search"
@click="handleQuery"
>
查询
</el-button>
<el-button
plain
size="mini"
type="warning"
icon="el-icon-refresh"
@click="resetQuery"
>
重置
</el-button>
<el-button
plain
size="mini"
type="success"
icon="el-icon-download"
@click="handleExport"
>
导出
</el-button>
</el-form-item>
</el-form>
<el-table
border
stripe
:data="nameListData"
style="width: 100%"
:header-cell-style="tableHeaderStyle"
:cell-style="tableCellStyle"
>
<el-table-column
align="center"
:key="item.prop"
:prop="item.prop"
:label="item.label"
show-overflow-tooltip
v-for="item in columnData"
/>
</el-table>
<!-- <div style="padding-right: 20px">
<pagination
:total="total"
@pagination="getNameListData"
:page.sync="nameListQueryParams.pageNum"
:limit.sync="nameListQueryParams.pageSize"
/>
</div> -->
</div>
</div>
</template>
<script>
export default {
name: 'SubCount',
props: {},
data() {
return {
total: 100,
nameListQueryParams: {
entryTime: '',
pageNum: 1,
pageSize: 10,
},
nameListData: [
{
entryTime: '2025-01-01',
exitTime: '2025-01-01',
contractName: '工程1',
subcontractorName: '分包1',
totalEntryCount: 10,
},
{
entryTime: '2025-01-01',
exitTime: '2025-01-01',
contractName: '工程1',
subcontractorName: '分包1',
totalEntryCount: 10,
},
],
columnData: [
{
label: '分包单位',
prop: 'entryTime',
},
{
label: '班组',
prop: 'exitTime',
},
{
label: '姓名',
prop: 'subcontractorName',
},
{
label: '性别',
prop: 'totalEntryCount',
},
{
label: '职务/工种',
prop: 'totalEntryCount',
},
{
label: '发证单位及证书号',
prop: 'totalEntryCount',
},
{
label: '有效期',
prop: 'totalEntryCount',
},
{
label: '性别',
prop: 'totalEntryCount',
},
{
label: '公民身份证号',
prop: 'totalEntryCount',
},
{
label: '户籍地址',
prop: 'totalEntryCount',
},
{
label: '手机号',
prop: 'totalEntryCount',
},
{
label: '入场时间',
prop: 'totalEntryCount',
},
{
label: '离场时间',
prop: 'totalEntryCount',
},
{
label: '在岗情况',
prop: 'totalEntryCount',
},
{
label: '备注',
prop: 'totalEntryCount',
},
],
}
},
created() {},
watch: {},
methods: {
//
tableHeaderStyle() {
return {
backgroundColor: '#f5f7fa',
color: '#606266',
fontWeight: '500',
fontSize: '14px',
textAlign: 'center',
}
},
//
tableCellStyle() {
return {
fontSize: '14px',
color: '#606266',
padding: '12px 8px',
}
},
//
handleQuery() {
// this.getAttInfoData()
},
//
resetQuery() {
this.attInfoQueryParams = {
entryTime: '',
}
},
//
handleExport() {
// this.download(
// '/bmw/workerLight/attExportByWorker',
// {
// ...this.attInfoQueryParams,
// },
// '.xlsx',
// )
},
//
getNameListData() {
// this.getAttInfoData()
},
},
}
</script>
<style lang="scss" scoped>
@import '@/assets/styles/variables.scss';
.section-container {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
overflow: hidden;
// padding: 20px 0;
.section-header {
padding: 20px 24px 16px;
border-bottom: 1px solid #f0f0f0;
.section-title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 600;
color: #1f2937;
.title-indicator {
width: 4px;
height: 20px;
background: #3b82f6;
border-radius: 2px;
margin-right: 12px;
}
}
}
.table-container {
padding: 0;
::v-deep .el-table {
border: none;
.el-table__header-wrapper {
.el-table__header {
th {
border-bottom: 1px solid #e4e7ed;
border-right: 1px solid #e4e7ed;
&:last-child {
border-right: none;
}
}
}
}
.el-table__body-wrapper {
.el-table__body {
tr {
&:hover {
background-color: #f8f9fa;
}
td {
border-bottom: 1px solid #f0f0f0;
border-right: 1px solid #f0f0f0;
&:last-child {
border-right: none;
}
}
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,92 @@
<template>
<!-- 三表一册表格 -->
<div class="sub-team-card-container">
<div class="section-header">
<span>"三表一册"清单</span>
</div>
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="农名工花名册" name="1" />
<el-tab-pane label="农民工实名制工资信息报审表" name="2" />
<el-tab-pane label="分包人员考勤明细表" name="3" />
<el-tab-pane label="农民工工资支付表" name="4" />
</el-tabs>
<div class="section-content">
<component :is="componentsList[activeName]" />
</div>
</div>
</template>
<script>
import DialogModel from '@/components/DialogModel/index.vue'
import NameList from './nameList.vue'
import WageInfo from './wage-info.vue'
import AttDetails from './att-details.vue'
import WagePay from './wage-pay.vue'
export default {
name: 'SubTeamCard',
components: {
DialogModel,
NameList,
WageInfo,
AttDetails,
WagePay,
},
data() {
return {
activeName: '1',
componentsList: {
1: 'NameList',
2: 'WageInfo',
3: 'AttDetails',
4: 'WagePay',
},
}
},
methods: {
handleClick(tab, event) {
console.log(tab, event)
this.activeName = tab.name
},
},
}
</script>
<style lang="scss" scoped>
@import '@/assets/styles/variables.scss';
.sub-team-card-container {
margin-bottom: 20px;
padding-bottom: 20px;
border-radius: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
background-color: #fff;
border: 1px solid #f0f0f0;
.section-header {
padding: 16px 10px;
font-size: 18px;
font-weight: 600;
color: #000;
font-family: 'PingFang SC';
background-color: #f5f7fa;
border-bottom: 1px solid #f0f0f0;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
}
.section-content {
padding: 0 20px;
}
}
::v-deep .el-tabs__header {
padding: 20px;
font-weight: bold;
}
::v-deep .el-tabs__item {
font-weight: 600;
font-size: 16px;
}
</style>

View File

@ -0,0 +1,289 @@
<template>
<!-- 工资信息 -->
<div class="section-container">
<div class="table-container">
<el-form
:inline="true"
label-width="auto"
:model="nameListQueryParams"
style="margin-top: 20px; padding-left: 20px"
>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入银行卡号"
/>
</el-form-item>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入班组"
/>
</el-form-item>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入姓名"
/>
</el-form-item>
<el-form-item>
<el-button
size="mini"
type="primary"
icon="el-icon-search"
@click="handleQuery"
>
查询
</el-button>
<el-button
plain
size="mini"
type="warning"
icon="el-icon-refresh"
@click="resetQuery"
>
重置
</el-button>
<el-button
plain
size="mini"
type="success"
icon="el-icon-download"
@click="handleExport"
>
导出
</el-button>
</el-form-item>
</el-form>
<el-table
border
stripe
:data="nameListData"
style="width: 100%"
:header-cell-style="tableHeaderStyle"
:cell-style="tableCellStyle"
>
<el-table-column
align="center"
:key="item.prop"
:prop="item.prop"
:label="item.label"
show-overflow-tooltip
v-for="item in columnData"
/>
</el-table>
<!-- <div style="padding-right: 20px">
<pagination
:total="total"
@pagination="getNameListData"
:page.sync="nameListQueryParams.pageNum"
:limit.sync="nameListQueryParams.pageSize"
/>
</div> -->
</div>
</div>
</template>
<script>
export default {
name: 'WageInfo',
props: {},
data() {
return {
total: 100,
nameListQueryParams: {
entryTime: '',
pageNum: 1,
pageSize: 10,
},
nameListData: [
{
entryTime: '2025-01-01',
exitTime: '2025-01-01',
contractName: '工程1',
subcontractorName: '分包1',
totalEntryCount: 10,
},
{
entryTime: '2025-01-01',
exitTime: '2025-01-01',
contractName: '工程1',
subcontractorName: '分包1',
totalEntryCount: 10,
},
],
columnData: [
{
label: '姓名',
prop: 'entryTime',
},
{
label: '所在班组',
prop: 'exitTime',
},
{
label: '身份证号',
prop: 'subcontractorName',
},
{
label: '开户银行',
prop: 'totalEntryCount',
},
{
label: '收款银行联行号',
prop: 'totalEntryCount',
},
{
label: '银行卡号',
prop: 'totalEntryCount',
},
{
label: '工资标准(元/日)',
prop: 'totalEntryCount',
},
{
label: '支付周期',
prop: 'totalEntryCount',
},
{
label: '支付日期',
prop: 'totalEntryCount',
},
{
label: '户籍地址',
prop: 'totalEntryCount',
},
{
label: '联系方式',
prop: 'totalEntryCount',
},
{
label: '备注',
prop: 'totalEntryCount',
},
],
}
},
created() {},
watch: {},
methods: {
//
tableHeaderStyle() {
return {
backgroundColor: '#f5f7fa',
color: '#606266',
fontWeight: '500',
fontSize: '14px',
textAlign: 'center',
}
},
//
tableCellStyle() {
return {
fontSize: '14px',
color: '#606266',
padding: '12px 8px',
}
},
//
handleQuery() {
// this.getAttInfoData()
},
//
resetQuery() {
this.attInfoQueryParams = {
entryTime: '',
}
},
//
handleExport() {
// this.download(
// '/bmw/workerLight/attExportByWorker',
// {
// ...this.attInfoQueryParams,
// },
// '.xlsx',
// )
},
//
getNameListData() {
// this.getAttInfoData()
},
},
}
</script>
<style lang="scss" scoped>
@import '@/assets/styles/variables.scss';
.section-container {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
overflow: hidden;
// padding: 20px 0;
.section-header {
padding: 20px 24px 16px;
border-bottom: 1px solid #f0f0f0;
.section-title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 600;
color: #1f2937;
.title-indicator {
width: 4px;
height: 20px;
background: #3b82f6;
border-radius: 2px;
margin-right: 12px;
}
}
}
.table-container {
padding: 0;
::v-deep .el-table {
border: none;
.el-table__header-wrapper {
.el-table__header {
th {
border-bottom: 1px solid #e4e7ed;
border-right: 1px solid #e4e7ed;
&:last-child {
border-right: none;
}
}
}
}
.el-table__body-wrapper {
.el-table__body {
tr {
&:hover {
background-color: #f8f9fa;
}
td {
border-bottom: 1px solid #f0f0f0;
border-right: 1px solid #f0f0f0;
&:last-child {
border-right: none;
}
}
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,337 @@
<template>
<!-- 工资支付 -->
<div class="section-container">
<div class="table-container">
<el-form
:inline="true"
label-width="auto"
:model="nameListQueryParams"
style="margin-top: 20px; padding-left: 20px"
>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入银行卡号"
/>
</el-form-item>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入班组"
/>
</el-form-item>
<el-form-item>
<el-input
v-model="nameListQueryParams.entryTime"
placeholder="请输入姓名"
/>
</el-form-item>
<el-form-item>
<el-button
size="mini"
type="primary"
icon="el-icon-search"
@click="handleQuery"
>
查询
</el-button>
<el-button
plain
size="mini"
type="warning"
icon="el-icon-refresh"
@click="resetQuery"
>
重置
</el-button>
<el-button
plain
size="mini"
type="success"
icon="el-icon-download"
@click="handleExport"
>
导出
</el-button>
<el-button
size="mini"
:icon="isEdit ? 'el-icon-check' : 'el-icon-edit'"
:type="isEdit ? 'success' : 'primary'"
@click="onHandleEditWagePay"
>
{{ isEdit ? '保存' : '修改' }}-其中代扣/代缴实发工资
</el-button>
</el-form-item>
</el-form>
<el-table
border
stripe
:data="nameListData"
style="width: 100%"
:header-cell-style="tableHeaderStyle"
:cell-style="tableCellStyle"
>
<el-table-column
align="center"
:key="item.prop"
:prop="item.prop"
:label="item.label"
show-overflow-tooltip
:width="item.width"
v-for="item in columnData"
>
<template slot-scope="scope">
<el-input
clearable
style="width: 100px"
v-model="scope.row[item.prop]"
v-if="
(item.prop === 'dk' || item.prop === 'sf') &&
isEdit
"
/>
<span v-else>{{ scope.row[item.prop] }}</span>
</template>
</el-table-column>
</el-table>
<!-- <div style="padding-right: 20px">
<pagination
:total="total"
@pagination="getNameListData"
:page.sync="nameListQueryParams.pageNum"
:limit.sync="nameListQueryParams.pageSize"
/>
</div> -->
</div>
</div>
</template>
<script>
export default {
name: 'WagePay',
props: {},
data() {
return {
isEdit: false,
total: 100,
nameListQueryParams: {
entryTime: '',
pageNum: 1,
pageSize: 10,
},
nameListData: [
{
entryTime: '2025-01-01',
exitTime: '2025-01-01',
contractName: '工程1',
subcontractorName: '分包1',
totalEntryCount: 10,
dk: 10,
sf: 10,
},
{
entryTime: '2025-01-01',
exitTime: '2025-01-01',
contractName: '工程1',
subcontractorName: '分包1',
totalEntryCount: 10,
dk: 10,
sf: 10,
},
],
columnData: [
{
label: '姓名',
prop: 'entryTime',
},
{
label: '身份证号',
prop: 'exitTime',
},
{
label: '所在班组',
prop: 'subcontractorName',
},
{
label: '岗位',
prop: 'totalEntryCount',
},
{
label: '出勤天数',
prop: 'totalEntryCount',
},
{
label: '应发工资',
prop: 'totalEntryCount',
},
{
label: '其中代扣/代缴',
prop: 'dk',
width: 140,
},
{
label: '实发工资',
prop: 'sf',
width: 140,
},
{
label: '开户银行',
prop: 'totalEntryCount',
},
{
label: '收款银行联行号',
prop: 'totalEntryCount',
},
{
label: '是否与劳动合同约定一致',
prop: 'totalEntryCount',
},
{
label: '本人签字',
prop: 'totalEntryCount',
},
{
label: '备注',
prop: 'totalEntryCount',
},
{
label: '转账日期',
prop: 'totalEntryCount',
},
{
label: '银行凭证号',
prop: 'totalEntryCount',
},
],
}
},
created() {},
watch: {},
methods: {
//
tableHeaderStyle() {
return {
backgroundColor: '#f5f7fa',
color: '#606266',
fontWeight: '500',
fontSize: '14px',
textAlign: 'center',
}
},
//
tableCellStyle() {
return {
fontSize: '14px',
color: '#606266',
padding: '12px 8px',
}
},
//
handleQuery() {
// this.getAttInfoData()
},
//
resetQuery() {
this.attInfoQueryParams = {
entryTime: '',
}
},
//
handleExport() {
// this.download(
// '/bmw/workerLight/attExportByWorker',
// {
// ...this.attInfoQueryParams,
// },
// '.xlsx',
// )
},
//
getNameListData() {
// this.getAttInfoData()
},
// -/
onHandleEditWagePay() {
this.isEdit = !this.isEdit
},
},
}
</script>
<style lang="scss" scoped>
@import '@/assets/styles/variables.scss';
.section-container {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
overflow: hidden;
// padding: 20px 0;
.section-header {
padding: 20px 24px 16px;
border-bottom: 1px solid #f0f0f0;
.section-title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 600;
color: #1f2937;
.title-indicator {
width: 4px;
height: 20px;
background: #3b82f6;
border-radius: 2px;
margin-right: 12px;
}
}
}
.table-container {
padding: 0;
::v-deep .el-table {
border: none;
.el-table__header-wrapper {
.el-table__header {
th {
border-bottom: 1px solid #e4e7ed;
border-right: 1px solid #e4e7ed;
&:last-child {
border-right: none;
}
}
}
}
.el-table__body-wrapper {
.el-table__body {
tr {
&:hover {
background-color: #f8f9fa;
}
td {
border-bottom: 1px solid #f0f0f0;
border-right: 1px solid #f0f0f0;
&:last-child {
border-right: none;
}
}
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,19 @@
<template>
<!-- 月份详情 -->
<div class="app-container">
<HeaderInfo />
<ThreeOneTable />
</div>
</template>
<script>
import HeaderInfo from './components/header-info.vue'
import ThreeOneTable from './components/three-one-table.vue'
export default {
name: 'MonthDetail',
components: {
HeaderInfo,
ThreeOneTable,
},
}
</script>