This commit is contained in:
Teo
2025-09-16 16:52:44 +08:00
13 changed files with 223 additions and 110 deletions

View File

@ -155,7 +155,7 @@ export const coryEngineeringList = (query: any): AxiosPromise<any[]> => {
*/
export const obtainTheVersion = (query: any) => {
return request({
url: '/cailiaoshebei/mrpBase/obtainTheVersion',
url: '/design/billofquantitiesVersions/obtainAllClassification',
method: 'get',
params: query
});

View File

@ -66,6 +66,7 @@ export interface ConstructionSchedulePlanForm extends BaseEntity {
*/
id?: string | number;
parentId?: string | number;
projectStructureName?: string;
/**
* 项目ID
*/

View File

@ -212,5 +212,50 @@ export function download(url: string, params: any, fileName: string, isHeader?:
downloadLoadingInstance.close();
});
}
/**
* GET 下载方法
* @param url 请求地址
* @param params 请求参数
* @param fileName 保存文件名
* @param isHeader 是否使用 json header
*/
export function downloadGet(url: string, params: any, fileName: string, isHeader?: boolean) {
downloadLoadingInstance = ElLoading.service({
text: '正在下载数据,请稍候',
background: 'rgba(0, 0, 0, 0.7)'
});
// 拼接参数
let query = tansParams(params);
if (query) {
url += '?' + query;
}
const config = {
headers: isHeader ? { 'Content-Type': 'application/json' } : { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob' as const
};
return service
.get(url, config)
.then(async (resp: any) => {
const isLogin = blobValidate(resp);
if (isLogin) {
const blob = new Blob([resp]);
FileSaver.saveAs(blob, fileName);
} else {
const resText = await resp.data.text();
const rspObj = JSON.parse(resText);
const errMsg = (rspObj && (rspObj.msg || rspObj.message)) || '下载失败';
ElMessage.error(errMsg);
}
downloadLoadingInstance.close();
})
.catch((err: any) => {
console.error(err);
ElMessage.error('下载文件出现错误,请联系管理员!');
downloadLoadingInstance.close();
});
}
// 导出 axios 实例
export default service;

View File

@ -74,6 +74,11 @@ export const formatPrice = (price, show = true) => {
const fixedNum = num.toFixed(4);
const [integer, decimal] = fixedNum.split('.');
// 检查小数部分是否为0
if (decimal === '0000') {
return `${integer}.00`;
}
// 千分位处理
const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ',');

View File

@ -23,7 +23,7 @@
v-for="(item, i) in weatherList"
:key="i"
class="weather-item"
:style="{ transform: `translateY(-${offsetY}px)`, transition: transition }"
:style="{ transform: `translateY(-${offsetY}vw)`, transition: transition }"
>
<img :src="`/assets/demo/${item.icon}.png`" alt="" />
<div>{{ item.weather }}{{ item.tempMin }}°/{{ item.tempMax }}°</div>
@ -39,7 +39,7 @@
<!-- 右侧管理系统图标 + 文字 -->
<div class="right-section">
<img src="@/assets/large/setting.png" alt="设置图标" />
<span>管理系统</span>
<span style="width: 5vw">管理系统</span>
</div>
<!-- 分割线 -->
<div class="divider">
@ -89,7 +89,7 @@ const emit = defineEmits(['changePage']);
const safetyDay = ref<number>(0);
const weatherList = ref<Weather[]>([]);
const timer = ref<number | null>(0);
const offsetY = ref<number>(0);
const offsetY = ref<any>(0);
const curIndex = ref(0);
const transition = ref('transform 0.5s ease');
const pendingPause = ref(false);
@ -119,7 +119,7 @@ function judgeDayOrNight(sunRise: string, sunSet: string) {
const setWeatherScroll = () => {
curIndex.value += 1;
transition.value = 'transform 0.3s ease';
offsetY.value = curIndex.value * 60;
offsetY.value = curIndex.value * 2;
if (curIndex.value === weatherList.value.length - 1) {
setTimeout(() => {
@ -232,13 +232,13 @@ onUnmounted(() => {
.title > div:first-child {
/* 第一个子元素的样式 */
font-size: 38px;
font-size: 2vw;
letter-spacing: 0.1em;
}
.title > div:last-child {
/* 最后一个子元素的样式 */
font-size: 14px;
font-size: 1vw;
}
/* 顶部栏容器Flex 水平布局 + 垂直居中 */
@ -260,22 +260,25 @@ onUnmounted(() => {
align-items: center;
.weather-list {
height: 60px;
height: 2vw;
overflow: hidden;
.weather-item {
height: 60px;
line-height: 60px;
height: 2vw;
display: flex;
align-items: center;
justify-content: center;
// padding: 10px 0;
// box-sizing: border-box;
font-size: 0.8vw;
& > div:last-child {
margin-left: 10px;
}
img {
width: 50px;
height: 50px;
width: 3vw;
height: 3vw;
}
}
}
@ -305,10 +308,12 @@ onUnmounted(() => {
/* 右侧区域(管理系统):图标 + 文字水平排列 */
.right-section {
width: 5.5vw;
display: flex;
align-items: center;
justify-content: center;
font-family: 'AlimamaShuHeiTi', sans-serif;
font-size: 20px;
font-size: 1vw;
cursor: pointer;
}

View File

@ -67,6 +67,17 @@
</el-tooltip>
</span>
</el-col>
<!-- <el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete()"
v-hasPermi="['formalities:formalitiesAreConsolidated:remove']"
>删除</el-button
>
</el-col> -->
<!-- <el-col :span="1.5">
<el-button
type="success"
@ -93,7 +104,7 @@
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="手续办理清单" align="left" prop="formalitiesName">
<template #default="scope">
<div>{{ scope.row.formalitiesName }}</div>
{{ scope.row.formalitiesName }}
</template>
</el-table-column>
<el-table-column label="计划开始时间" align="center" prop="planTheStartTime" width="180">
@ -130,7 +141,7 @@
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" fixed="right">
<template #default="scope">
<div v-if="scope.row.formalitiesPid">
<div v-if="scope.row.formalitiesPid && scope.row.processingStatus != '不需要办理'">
<el-button
link
type="primary"
@ -151,6 +162,9 @@
v-hasPermi="['formalities:formalitiesAreConsolidated:edit']"
>修改状态</el-button
>
<!-- <el-button link type="danger" icon="Delete" v-if="scope.row.processingStatus == '待开始'" @click="handleDelete(scope.row)"
>删除</el-button
> -->
</div>
</template>
</el-table-column>
@ -242,6 +256,7 @@
<el-option label="待开始" value="待开始" />
<el-option label="处理中" value="处理中" />
<el-option label="已完成" value="已完成" />
<el-option label="不需要办理" value="不需要办理" />
</el-select>
</el-form-item>
</el-form>
@ -546,6 +561,16 @@ const handleUpdateStatus = async (row?: FormalitiesAreConsolidatedVO) => {
updateStatusVisible.value = true;
};
const handleDelete = async (row?: any) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除数据项?').finally(() => (fileLoading.value = false));
fileLoading.value = true;
await delFormalitiesAreConsolidated(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
const submitStatus = async () => {
statusFormRef.value?.validate(async (valid: boolean) => {
if (valid) {

View File

@ -23,7 +23,7 @@
v-for="(item, i) in weatherList"
:key="i"
class="weather-item"
:style="{ transform: `translateY(-${offsetY}px)`, transition: transition }"
:style="{ transform: `translateY(-${offsetY}vw)`, transition: transition }"
>
<img :src="`/assets/demo/${item.icon}.png`" alt="" />
<div>{{ item.weather }}{{ item.tempMin }}°/{{ item.tempMax }}°</div>
@ -79,7 +79,7 @@ const userStore = useUserStoreHook();
const currentProject = computed(() => userStore.selectedProject);
// 天气轮播相关变量
const weatherList = ref<WeatherData[]>([]);
const weatherList = ref<any[]>([]);
const offsetY = ref<number>(0);
const curIndex = ref(0);
const transition = ref('transform 0.5s ease');
@ -103,7 +103,7 @@ function judgeDayOrNight(sunRise: string, sunSet: string) {
const setWeatherScroll = () => {
curIndex.value += 1;
transition.value = 'transform 0.3s ease';
offsetY.value = curIndex.value * 60; // 每个天气项高度60px需和样式一致
offsetY.value = curIndex.value * 2; // 每个天气项高度60px需和样式一致
// 轮播到最后一项时,无缝衔接回第一项
if (curIndex.value === weatherList.value.length - 1) {
@ -160,7 +160,7 @@ const getWeatherData = async () => {
weatherList.value = res.data;
// 处理每一天的天气(白天/夜晚切换图标和状态)
weatherList.value.forEach((item) => {
weatherList.value.forEach((item: any) => {
const isDay = judgeDayOrNight(item.sunRise, item.sunSet);
item.status = isDay ? item.dayStatus : item.nightStatus;
item.icon = isDay ? item.dayIcon : item.nightIcon;
@ -250,13 +250,13 @@ onUnmounted(() => {
.title > div:first-child {
/* 第一个子元素的样式 */
font-size: 38px;
font-size: 2vw;
letter-spacing: 0.1em;
}
.title > div:last-child {
/* 最后一个子元素的样式 */
font-size: 14px;
font-size: 1vw;
}
/* 顶部栏容器Flex 水平布局 + 垂直居中 */
@ -278,22 +278,25 @@ onUnmounted(() => {
align-items: center;
.weather-list {
height: 60px;
height: 2vw;
overflow: hidden;
.weather-item {
height: 60px;
line-height: 60px;
height: 2vw;
display: flex;
align-items: center;
justify-content: center;
// padding: 10px 0;
// box-sizing: border-box;
font-size: 0.8vw;
& > div:last-child {
margin-left: 10px;
}
img {
width: 50px;
height: 50px;
width: 3vw;
height: 3vw;
}
}
}
@ -323,10 +326,12 @@ onUnmounted(() => {
/* 右侧区域(管理系统):图标 + 文字水平排列 */
.right-section {
width: 5.5vw;
display: flex;
align-items: center;
justify-content: center;
font-family: 'AlimamaShuHeiTi', sans-serif;
font-size: 20px;
font-size: 1vw;
cursor: pointer;
}

View File

@ -117,7 +117,7 @@
<el-table-column prop="batchNumber" align="center" label="版本号 " width="200">
<template #default="scope">
<el-select v-model="scope.row.batchNumber" placeholder="请选择" @change="(val) => selectNameVersion(val, scope.row, scope.$index)">
<el-option v-for="item in versionList" :key="item.versions" :label="item.versions" :value="item.versions" />
<el-option v-for="item in versionList" :key="item.versions" :label="item.name" :value="item.sid" />
</el-select>
</template>
</el-table-column>
@ -692,10 +692,10 @@ const handleAudit = async () => {
};
/** 获取物资列表(按版本号筛选) */
const getNameList = (versions: string) => {
const getNameList = (sid: string) => {
coryEngineeringList({
projectId: currentProject.value?.id,
versions
sid
})
.then((res: any) => {
nameList.value = res.data || [];
@ -750,7 +750,7 @@ const listeningProject = watch(
if (newId !== oldId && newId) {
queryParams.value.mainData.projectId = newId;
queryParams.value.batchData.projectId = newId;
form.value.mrpBaseBo.projectId = newId;
form.value.mrpBaseBo.projectId = newId as number;
getList();
getVersion(); // 重新获取对应项目的版本号
}

View File

@ -27,6 +27,21 @@
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['progress:constructionSchedulePlan:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<file-upload
upload-url="/progress/constructionSchedulePlan/readTemplate"
v-model="file"
:limit="1"
:data="{ projectId: queryParams.projectId }"
:file-type="['xls', 'xlsx']"
:on-upload-success="handleSuccess"
>
<el-button type="primary" plain icon="upload">导入</el-button>
</file-upload>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="Filter" @click="handleExport">导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
</el-col>
@ -126,22 +141,10 @@
<el-date-picker clearable v-model="form.planEndDate" type="date" value-format="YYYY-MM-DD" placeholder="选择预计结束时间" />
</el-form-item>
<el-form-item label="实际开始时间" prop="practicalStartDate">
<el-date-picker
clearable
v-model="form.practicalStartDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择实际开始时间"
/>
<el-date-picker clearable v-model="form.practicalStartDate" type="date" value-format="YYYY-MM-DD" placeholder="选择实际开始时间" />
</el-form-item>
<el-form-item label="实际结束时间" prop="practicalEndDate">
<el-date-picker
clearable
v-model="form.practicalEndDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择实际结束时间"
/>
<el-date-picker clearable v-model="form.practicalEndDate" type="date" value-format="YYYY-MM-DD" placeholder="选择实际结束时间" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="form.status" placeholder="请选择状态">
@ -221,6 +224,7 @@ const initFormData = {
remark: undefined,
projectStructureName: undefined
};
const file = ref();
const data = reactive<PageData<ConstructionSchedulePlanForm, ConstructionSchedulePlanQuery>>({
form: { ...initFormData },
@ -279,6 +283,17 @@ const cancel = () => {
dialog.visible = false;
};
const handleExport = async () => {
const ids = queryParams.value.projectId;
proxy?.download('/progress/constructionSchedulePlan/exportTemplate/' + ids, {}, `施工里程碑计划模版.xlsx`, true);
};
const handleSuccess = () => {
console.log(111);
proxy.$modal.msgSuccess('操作成功');
getList();
};
// 表单重置
const reset = () => {
form.value = { ...initFormData };

View File

@ -31,6 +31,7 @@
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
<el-button icon="Download" type="warning" @click="onExport">导出</el-button>
</el-form-item>
</el-form>
</el-card>
@ -170,6 +171,17 @@ const dialog = reactive<DialogOption>({
details: false,
title: ''
});
const now = new Date();
// 获取年份4位数字
const year = now.getFullYear();
// 获取月份注意getMonth() 返回 0-11需要 +1 转换为 1-12
const month = now.getMonth() + 1;
// 格式化月份为两位数不足两位补0拼接成年月字符串
const currentYearMonth = `${year}-${month.toString().padStart(2, '0')}`;
const echartsOption = ref<any>({});
const exportForm = reactive({
fuzzyQuery: undefined,

View File

@ -1,37 +1,35 @@
export interface BusSalaryDetailsTableColumns {
id:number
sfzNumber:string; // 身份证
name:string; // 户名
account:string; // 账户
sumDuration:number; // 当月总时长
salary:number; // 薪水(天)
dateOfIssue:string; // 发放年月
lister:string; // 制表人
createdAt:string; // 创建时间
id: number;
sfzNumber: string; // 身份证
name: string; // 户名
account: string; // 账户
sumDuration: number; // 当月总时长
salary: number; // 薪水(天)
dateOfIssue: string; // 发放年月
lister: string; // 制表人
createdAt: string; // 创建时间
}
export interface BusSalaryDetailsInfoData {
id:number|undefined; // 主键ID
sfzNumber:string|undefined; // 身份证
name:string|undefined; // 户名
account:string|undefined; // 账户
sumDuration:number|undefined; // 当月总时长
salary:number|undefined; // 薪水(天)
projectId:number|undefined; // 项目id
teamId:number|undefined; // 班组id
projectName:string|undefined; // 项目名称
teamName:string|undefined; // 班组名称
dateOfIssue:string|undefined; // 发放年月
lister:string|undefined; // 制表人
createdAt:string|undefined; // 创建时间
updatedAt:string|undefined; // 更新时间
deletedAt:string|undefined; // 删除时间
id: number | undefined; // 主键ID
sfzNumber: string | undefined; // 身份证
name: string | undefined; // 户名
account: string | undefined; // 账户
sumDuration: number | undefined; // 当月总时长
salary: number | undefined; // 薪水(天)
projectId: number | undefined; // 项目id
teamId: number | undefined; // 班组id
projectName: string | undefined; // 项目名称
teamName: string | undefined; // 班组名称
dateOfIssue: string | undefined; // 发放年月
lister: string | undefined; // 制表人
createdAt: string | undefined; // 创建时间
updatedAt: string | undefined; // 更新时间
deletedAt: string | undefined; // 删除时间
}
export interface BusSalaryDetailsTableDataState {
ids:any[];
ids: any[];
tableData: {
data: Array<BusSalaryDetailsTableColumns>;
total: number;
@ -39,19 +37,18 @@ export interface BusSalaryDetailsTableDataState {
param: {
pageNum: number;
pageSize: number;
id: number|undefined;
sfzNumber: string|undefined;
projectId: number|undefined;
teamId: number|undefined;
id: number | undefined;
sfzNumber: string | undefined;
projectId: number | undefined;
teamId: number | undefined;
dateRange: string[];
};
};
}
export interface BusSalaryDetailsEditState{
loading:boolean;
export interface BusSalaryDetailsEditState {
loading: boolean;
isShowDialog: boolean;
formData:BusSalaryDetailsInfoData;
formData: BusSalaryDetailsInfoData;
rules: object;
}

View File

@ -4,26 +4,26 @@
<div class="system-busSalaryDetails-search mb15">
<el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="100px">
<el-row>
<el-col :span="4" class="colBlock">
<el-col :span="1.5" class="colBlock">
<el-form-item label="身份证" prop="sfzNumber">
<el-input v-model="tableData.param.sfzNumber" placeholder="请输入身份证" clearable @keyup.enter.native="busSalaryDetailsList" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-col :span="1.5">
<el-form-item label="项目选择" prop="projectId">
<el-select v-model="tableData.param.projectId" placeholder="请选择项目" @change="onChangeProject">
<el-option v-for="(item, i) of projectList" :key="i" :label="item.shortName" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="4">
<el-col :span="1.5">
<el-form-item label="班组选择" prop="teamId">
<el-select v-model="tableData.param.teamId" @change="onChangeTeam" :disabled="!tableData.param.projectId" placeholder="请选择班组">
<el-option v-for="(item, i) of TeamList" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-col :span="1.5">
<el-form-item label="发放年月" prop="dateOfIssue">
<el-date-picker
v-model="tableData.param.dateOfIssue"
@ -34,7 +34,7 @@
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-col :span="1.5">
<el-form-item>
<el-button type="primary" @click="busSalaryDetailsList"
><el-icon><Search /></el-icon>搜索</el-button

View File

@ -23,7 +23,7 @@
v-for="(item, i) in weatherList"
:key="i"
class="weather-item"
:style="{ transform: `translateY(-${offsetY}px)`, transition: transition }"
:style="{ transform: `translateY(-${offsetY}vw)`, transition: transition }"
>
<img :src="`/assets/demo/${item.icon}.png`" alt="" />
<div>{{ item.weather }}{{ item.tempMin }}°/{{ item.tempMax }}°</div>
@ -39,7 +39,7 @@
<!-- 右侧管理系统图标 + 文字 -->
<div class="right-section">
<img src="@/assets/large/setting.png" alt="设置图标" />
<span>管理系统</span>
<span style="width: 5vw">管理系统</span>
</div>
<!-- 分割线 -->
<div class="divider">
@ -129,7 +129,7 @@ function judgeDayOrNight(sunRise: string, sunSet: string) {
const setWeatherScroll = () => {
curIndex.value += 1;
transition.value = 'transform 0.3s ease';
offsetY.value = curIndex.value * 60;
offsetY.value = curIndex.value * 2;
if (curIndex.value === weatherList.value.length - 1) {
setTimeout(() => {
@ -242,13 +242,13 @@ onUnmounted(() => {
.title > div:first-child {
/* 第一个子元素的样式 */
font-size: 38px;
font-size: 2vw;
letter-spacing: 0.1em;
}
.title > div:last-child {
/* 最后一个子元素的样式 */
font-size: 26px;
font-size: 1.5vw;
}
/* 顶部栏容器Flex 水平布局 + 垂直居中 */
@ -270,22 +270,23 @@ onUnmounted(() => {
align-items: center;
.weather-list {
height: 60px;
height: 2vw;
overflow: hidden;
.weather-item {
height: 60px;
line-height: 60px;
height: 2vw;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.8vw;
& > div:last-child {
margin-left: 10px;
}
img {
width: 50px;
height: 50px;
width: 3vw;
height: 3vw;
}
}
}
@ -315,10 +316,12 @@ onUnmounted(() => {
/* 右侧区域(管理系统):图标 + 文字水平排列 */
.right-section {
width: 5.5vw;
display: flex;
align-items: center;
justify-content: center;
font-family: 'AlimamaShuHeiTi', sans-serif;
font-size: 20px;
font-size: 1vw;
cursor: pointer;
}