This commit is contained in:
dhr
2025-08-29 14:55:47 +08:00
123 changed files with 8466 additions and 4077 deletions

View File

@ -12,9 +12,7 @@ VITE_APP_BASE_API = 'http://192.168.110.149:8899'
# 罗成
# VITE_APP_BASE_API = 'http://192.168.110.213:8899'
# 朱银
# VITE_APP_BASE_API = 'http://192.168.110.149:8899'
#曾涛
# VITE_APP_BASE_API = 'http://192.168.110.171:8899'
# VITE_APP_BASE_API = 'http://192.168.110.180:8899'
# 无人机接口地址

BIN
public/catalog.xlsx Normal file

Binary file not shown.

BIN
public/enterRoad.xlsx Normal file

Binary file not shown.

BIN
public/landBlock.xlsx Normal file

Binary file not shown.

View File

@ -19,3 +19,11 @@ onMounted(() => {
});
});
</script>
<style>
* {
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+/Edge */
user-select: none; /* Standard syntax */
}
</style>

View File

@ -91,3 +91,11 @@ export const getDetailsList = (query: any): AxiosPromise<any> => {
params: query
});
};
//获取版本详情
export const getVersionDetails = (id: any): AxiosPromise<any> => {
return request({
url: '/tender/tenderPlanLimitList/getVersionDetail/' + id,
method: 'get'
});
};

View File

@ -27,3 +27,11 @@ export const systemUserList = (query) => {
params: query
});
};
// 查询
export const desUserList = (query) => {
return request({
url: '/design/drawingreviewReceipts/desUser/list',
method: 'get',
params: query
});
};

View File

@ -56,7 +56,7 @@ export const fillOutTheDesignVerificationForm = (data) => {
export const drawingreviewReceipts = (data) => {
return request({
url: '/design/drawingreviewReceipts',
method: 'post',
method: 'put',
data
});
};
@ -96,3 +96,10 @@ export const drawingreview = (id) => {
method: 'get'
});
};
// 获取单据
export const getDrawingreviewReceipts = (id) => {
return request({
url: '/design/drawingreviewReceipts/review/' + id,
method: 'get'
});
};

View File

@ -5,6 +5,7 @@ import {
FormalitiesAreConsolidatedForm,
FormalitiesAreConsolidatedQuery
} from '@/api/formalities/formalitiesAreConsolidated/types';
import { ListOfFormalitiesQuery, ListOfFormalitiesVO } from '../listOfFormalities/types';
/**
* 查询合规性手续合账列表
@ -101,3 +102,17 @@ export const delFormalitiesAnnex = (id: string | number | Array<string | number>
method: 'delete'
});
};
/**
* 查询手续办理清单模板属性列表
* @param query
* @returns {*}
*/
export const getTemplateTreeList = (query?: any): AxiosPromise<ListOfFormalitiesVO[]> => {
return request({
url: '/formalities/formalitiesAreConsolidated/getTree',
method: 'get',
params: query
});
};

View File

@ -75,3 +75,12 @@ export const getWhetherItExists = (id: string | number): AxiosPromise<ListOfForm
}
});
};
//模版新增
export const addFormalities = (data: any): AxiosPromise<ListOfFormalitiesVO> => {
return request({
url: '/formalities/formalitiesAreConsolidated/addFormalities',
method: 'post',
data
});
};

View File

@ -15,7 +15,7 @@ export const totalAmount = () => {
/**
* 查询项目位置列表
*
*/ export const projectGis = (clientid) => {
*/ export const projectGis = (clientid?: any) => {
return request({
url: '/money/big/screen/project/gis',
method: 'get',
@ -57,7 +57,8 @@ export const totalAmount = () => {
/**
* 支出合同分析
*
*/ export const expensesAnalyze = (clientid) => {
*/
export const expensesAnalyze = (clientid) => {
return request({
url: '/money/big/screen/expenses/analyze',
method: 'get',
@ -79,14 +80,14 @@ export const totalAmount = () => {
export const monthMoney = () => {
return request({
url: '/money/big/screen/monthMoney',
method: 'get',
method: 'get'
});
};
// 现金流
export const monthCash = () => {
return request({
url: '/money/big/screen/monthCash',
method: 'get',
method: 'get'
});
};
// 现金流总和
@ -94,6 +95,6 @@ export const monthCash = () => {
export const cashTotal = () => {
return request({
url: '/money/big/screen/cashTotal',
method: 'get',
method: 'get'
});
};

View File

@ -160,3 +160,13 @@ export const obtainTheVersion = (query: any) => {
params: query
});
};
/**
* 获取到物资剩余量
*/
export const mrpBaseRemaining = (query: any) => {
return request({
url: '/cailiaoshebei/mrpBase/remaining',
method: 'get',
params: query
});
};

View File

@ -68,3 +68,10 @@ export const getMaterialName = (id: any) => {
method: 'get'
});
};
//获取出库记录
export const inventoryList = (id: any) => {
return request({
url: '/materials/materialIssue/inventory/list/' + id,
method: 'get'
});
};

View File

@ -61,3 +61,16 @@ export const delMaterialReceive = (id: string | number | Array<string | number>)
method: 'delete'
});
};
/**
* 获取合同列表数据
* @param id
*/
export const getContractNameList = (id: string | number | Array<string | number>) => {
return request({
url: '/materials/materialReceive/ctrList',
params: {
projectId: id
},
method: 'get'
});
};

View File

@ -3,9 +3,9 @@ import { AxiosPromise } from 'axios';
import { RouteRecordRaw } from 'vue-router';
// 获取路由
export function getRouters(): AxiosPromise<RouteRecordRaw[]> {
export function getRouters(id: string): AxiosPromise<RouteRecordRaw[]> {
return request({
url: '/system/menu/getRouters',
url: '/system/menu/getRouters/' + id,
method: 'get'
});
}

View File

@ -0,0 +1,63 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { NoticeVO, NoticeForm, NoticeQuery } from '@/api/message/notice/types';
/**
* 查询消息列表
* @param query
* @returns {*}
*/
export const listNotice = (query?: NoticeQuery): AxiosPromise<NoticeVO[]> => {
return request({
url: '/message/notice/list',
method: 'get',
params: query
});
};
/**
* 查询消息详细
* @param id
*/
export const getNotice = (id: string | number): AxiosPromise<NoticeVO> => {
return request({
url: '/message/notice/' + id,
method: 'get'
});
};
/**
* 新增消息
* @param data
*/
export const addNotice = (data: NoticeForm) => {
return request({
url: '/message/notice',
method: 'post',
data: data
});
};
/**
* 修改消息
* @param data
*/
export const updateNotice = (data: NoticeForm) => {
return request({
url: '/message/notice',
method: 'put',
data: data
});
};
/**
* 删除消息
* @param id
*/
export const delNotice = (id: string | number | Array<string | number>) => {
return request({
url: '/message/notice/' + id,
method: 'delete'
});
};

View File

@ -0,0 +1,156 @@
export interface NoticeVO {
/**
* 主键ID
*/
id: string | number;
/**
* 项目ID
*/
projectId: string | number;
/**
* 接收通知的用户ID
*/
recipientId: string | number;
/**
* 发送通知的用户ID系统通知 0
*/
senderId: string | number;
/**
* 配置id
*/
configId: string | number;
/**
* 详情id
*/
detailId: string | number;
/**
* 通知内容
*/
content: string;
/**
* 查看状态(0未读 1已读)
*/
viewStatus: string;
/**
* 查看时间
*/
viewTime: string;
/**
* 备注
*/
remark: string;
}
export interface NoticeForm extends BaseEntity {
/**
* 主键ID
*/
id?: string | number;
/**
* 项目ID
*/
projectId?: string | number;
/**
* 接收通知的用户ID
*/
recipientId?: string | number;
/**
* 发送通知的用户ID系统通知 0
*/
senderId?: string | number;
/**
* 配置id
*/
configId?: string | number;
/**
* 详情id
*/
detailId?: string | number;
/**
* 通知内容
*/
content?: string;
/**
* 查看状态(0未读 1已读)
*/
viewStatus?: string;
/**
* 查看时间
*/
viewTime?: string;
/**
* 备注
*/
remark?: string;
}
export interface NoticeQuery extends PageQuery {
/**
* 项目ID
*/
projectId?: string | number;
/**
* 接收通知的用户ID
*/
recipientId?: string | number;
/**
* 发送通知的用户ID系统通知 0
*/
senderId?: string | number;
/**
* 配置id
*/
configId?: string | number;
/**
* 详情id
*/
detailId?: string | number;
/**
* 通知内容
*/
content?: string;
/**
* 查看状态(0未读 1已读)
*/
viewStatus?: string;
/**
* 查看时间
*/
viewTime?: string;
/**
* 日期范围参数
*/
params?: any;
}

View File

@ -8,11 +8,10 @@ import { ProgressCategoryVO, ProgressCategoryForm, ProgressCategoryQuery } from
* @returns {*}
*/
export const listProgressCategory = (query?: ProgressCategoryQuery): AxiosPromise<ProgressCategoryVO[]> => {
export const listProgressCategory = (id?: string | number): AxiosPromise<any[]> => {
return request({
url: '/progress/progressCategory/list',
method: 'get',
params: query
url: '/progress/progressCategory/listByParent/' + id,
method: 'get'
});
};
@ -70,3 +69,30 @@ export const downloadProgressCategory = (data) => {
data
});
};
/**
* 查询分项工程单价下拉树结构
* @param query
* @returns {*}
*/
export const getCategoryTabList = (id?: string | number): AxiosPromise<any[]> => {
return request({
url: '/progress/progressCategory/listTopBySubProjectId/' + id,
method: 'get'
});
};
/**
* 查询分项工程单价外层结构
* @param query
* @returns {*}
*/
export const getCategoryList = (id?: string | number): AxiosPromise<any[]> => {
return request({
url: '/progress/progressCategory/list',
method: 'get',
params: {
parentId: id
}
});
};

View File

@ -97,6 +97,8 @@ export interface ProgressCategoryForm extends BaseEntity {
id?: string | number;
constructionPrice?: string | number;
ownerPrice?: string | number;
relevancyStructure?: string;
/**
* 父类别id
*/

View File

@ -1,6 +1,10 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { ProgressCategoryTemplateVO, ProgressCategoryTemplateForm, ProgressCategoryTemplateQuery } from '@/api/progress/progressCategoryTemplate/types';
import {
ProgressCategoryTemplateVO,
ProgressCategoryTemplateForm,
ProgressCategoryTemplateQuery
} from '@/api/progress/progressCategoryTemplate/types';
/**
* 查询进度类别模版列表
@ -61,3 +65,22 @@ export const delProgressCategoryTemplate = (id: string | number | Array<string |
method: 'delete'
});
};
export const getTabList = (id: string) => {
return request({
url: '/progress/progressCategoryTemplate/listSystemTop/' + id,
method: 'get'
});
};
/**
* 筛选查询进度类别模版列表
* @param parentId
* @returns {*}
*/
export const listProgressCategoryTemplateByParent = (parentId: string | number): AxiosPromise<ProgressCategoryTemplateVO[]> => {
return request({
url: '/progress/progressCategoryTemplate/listByParent/' + parentId,
method: 'get'
});
};

View File

@ -12,7 +12,7 @@ export interface ProgressCategoryTemplateVO {
* 计量方式0无 1数量 2百分比
*/
unitType: string;
parentId?: string | number;
/**
* 工作类型
*/
@ -39,7 +39,9 @@ export interface ProgressCategoryTemplateForm extends BaseEntity {
* 主键id
*/
id?: string | number;
parentId?: string | number;
constructionType?: string;
relevancyStructure?: string;
/**
* 父类别id
*/
@ -76,7 +78,8 @@ export interface ProgressCategoryTemplateQuery {
* 父类别id
*/
pid?: string | number;
parentId?: string | number;
constructionType?: string;
/**
* 类别名称
*/

View File

@ -28,10 +28,10 @@ export interface ContractorVO {
* 管理人联系电话
*/
custodianPhone: string;
/**
/**
* 分包类型
*/
contractorType?: string;
contractorType?: string;
/**
* 公司相关文件
@ -54,6 +54,14 @@ export interface ContractorForm extends BaseEntity {
* 主键id
*/
id?: string | number;
/**
* 供应商id
*/
supplierId?: string | number;
/**
* 供应商
*/
supplier?: string;
/**
* 主键id
@ -127,10 +135,10 @@ export interface ContractorQuery extends PageQuery {
* 管理人联系电话
*/
custodianPhone?: string;
/**
/**
* 分包类型
*/
contractorType?: string;
contractorType?: string;
/**
* 日期范围参数

View File

@ -186,3 +186,14 @@ export const uploadProjectFile = (data: any) => {
data: data
});
};
/**
* 切换项目
* @param id
*/
export const changeProject = (id: string | number) => {
return request({
url: '/project/project/changeProject/' + id,
method: 'get'
});
};

View File

@ -8,7 +8,7 @@ import { SupplierInputVO, SupplierInputForm, SupplierInputQuery } from '@/api/su
* @returns {*}
*/
export const listSupplierInput = (query?: SupplierInputQuery): AxiosPromise<SupplierInputVO[]> => {
export const listSupplierInput = (query?: any): AxiosPromise<SupplierInputVO[]> => {
return request({
url: '/supplierInput/supplierInput/list',
method: 'get',

View File

@ -61,3 +61,12 @@ export const delEnterRoad = (id: string | number | Array<string | number>) => {
method: 'delete'
});
};
// 道路信息导入
export const importEnterRoad = (projectId: any, data: any) => {
return request({
url: '/land/enterRoad/upload/' + projectId,
method: 'post',
data: data
});
};

View File

@ -76,3 +76,12 @@ export const delLandBlock = (id: string | number | Array<string | number>) => {
method: 'delete'
});
};
// 地块信息导入
export const importLandBlock = (projectId:any,data: any) => {
return request({
url: '/land/landBlock/upload/'+projectId,
method: 'post',
data: data
});
};

View File

@ -69,3 +69,13 @@ export const delLandTransferLedger = (id: string | number | Array<string | numbe
method: 'delete'
});
};
/**
* 获取详情
* @param id
*/
export const landTransferLedgerCount = (id: string | number | Array<string | number>) => {
return request({
url: '/land/landTransferLedger/count/' + id,
method: 'get'
});
};

View File

@ -68,3 +68,11 @@ export const delMenu = (menuId: string | number) => {
method: 'delete'
});
};
// 获取所有路由
export const getAllRouters = () => {
return request({
url: '/system/menu/getAllRouters',
method: 'get'
});
};

View File

@ -75,3 +75,11 @@ export function getRoleList(deptId?: number | string): AxiosPromise<any[]> {
}
});
}
// 获取部门下的项目列表
export function getProjectByDeptId(deptId?: number | string): AxiosPromise<any[]> {
return request({
url: '/system/dept/projectIdList/' + deptId,
method: 'get'
});
}

View File

@ -60,19 +60,20 @@ export interface UserForm {
nickName?: string;
password: string;
phonenumber?: string;
projectRoles?: any[];
email?: string;
sex?: string;
status: string;
remark?: string;
postIds: string[];
roleIds: string[];
filePath?: string;
}
export interface UserInfoVO {
user: UserVO;
roles: RoleVO[];
roleIds: string[];
projectRoles: any[];
posts: PostVO[];
postIds: string[];
roleGroup: string;

View File

@ -122,11 +122,10 @@ export const editStatus = (query: any): AxiosPromise<any> => {
data: query
});
};
//获取审核状态
export const getApproval = (id) => {
//获取版本详情
export const getVersionDetail = (id: any) => {
return request({
url: '/tender/tenderPlanLimitList/getVersionDetail',
method: 'get',
params: { versions: id }
url: '/tender/tenderPlanLimitList/getVersionDetail/' + id,
method: 'get'
});
};

View File

@ -11,6 +11,7 @@
:on-exceed="handleExceed"
:on-success="handleUploadSuccess"
:show-file-list="showFileList"
:on-preview="handlePreview"
:headers="headers"
class="upload-file-uploader"
:list-type="isConstruction ? 'picture-card' : 'text'"
@ -48,7 +49,13 @@
tag="ul"
@click.stop
>
<li style="margin-top: 10px" v-for="(file, index) in fileList" :key="file.uid" class="el-upload-list__item ele-upload-list__item-content">
<li
style="margin-top: 10px"
v-for="(file, index) in fileList"
:key="file.uid"
class="el-upload-list__item ele-upload-list__item-content"
v-if="autoUpload"
>
<el-link :href="`${file.url}`" :underline="false" target="_blank">
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
</el-link>
@ -213,31 +220,27 @@ watch(
);
// 上传前校检格式和大小
const handleBeforeUpload = (file: any) => {
// 校检文件类型
if (props.fileType.length) {
const fileName = file.name.split('.');
const fileExt = fileName[fileName.length - 1];
const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
if (!isTypeOk) {
proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`);
return false;
}
if (!validateFile(file)) return false;
proxy?.$modal.loading('正在上传文件,请稍候...');
number.value++;
return true;
};
//校检格式和大小
const validateFile = (file: File) => {
const ext = file.name.split('.').pop()?.toLowerCase();
if (props.fileType.length && !props.fileType.includes(ext!)) {
proxy?.$modal.msgError(`文件格式不正确,请上传 ${props.fileType.join('/')} 格式文件!`);
return false;
}
// 校检文件名是否包含特殊字符
if (file.name.includes(',')) {
proxy?.$modal.msgError('文件名不正确,不能包含英文逗号!');
return false;
}
// 校检文件大小
if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize;
if (!isLt) {
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
return false;
}
if (props.fileSize && file.size / 1024 / 1024 > props.fileSize) {
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
return false;
}
proxy?.$modal.loading('正在上传文件,请稍候...');
number.value++;
return true;
};
@ -278,13 +281,25 @@ const handleUploadSuccess = (res: any, file: UploadFileWithOssId) => {
uploadedSuccessfully(res);
};
const handleChange = (file: any, fileList: any) => {
const handleChange = (file: any, filelist: any) => {
if (!props.autoUpload) {
// 手动上传模式:在选中文件时拦截非法文件
const isValid = validateFile(file.raw || file);
if (!isValid) {
fileUploadRef.value?.handleRemove(file); // 直接移除非法文件
console.log(file, filelist, fileList.value);
fileList.value = [...fileList.value]; // 触发列表更新
return;
}
}
// 记录 status = 'ready' 的文件
if (file.status === 'ready') {
pendingFiles.value.push(file);
fileList.value = pendingFiles.value;
}
console.log(fileList.value);
emit('handleChange', file, fileList);
emit('handleChange', file, filelist);
};
// 删除文件
@ -294,6 +309,12 @@ const handleRemove = (file: any, fileList: any) => {
emit('handleRemove', file, fileList);
};
const handlePreview = (file: any) => {
if (file.url) {
window.open(file.url);
}
};
// 删除文件
const handleDelete = async (index: string | number, type?: string) => {
await proxy?.$modal.confirm('是否确认删除此文件?').finally();
@ -332,11 +353,6 @@ const uploadedSuccessfully = (res: any) => {
emit('update:modelValue', listToString(fileList.value));
proxy?.$modal.closeLoading();
}
// if (props.autoUpload && props.limit === fileList.value.length) {
// fileUploadRef.value?.clearFiles();
// fileList.value = [];
// emit('update:modelValue', ''); // 同步到外部 v-model
// }
props.onUploadSuccess?.(fileList.value, res);
};
@ -400,6 +416,11 @@ const submitUpload = async () => {
if (!pendingFiles.value.length) {
return 'noFile';
}
const validFiles = pendingFiles.value.filter((f: any) => validateFile(f.raw || f));
if (!validFiles.length) {
proxy?.$modal.msgError('没有符合条件的文件可上传');
return;
}
try {
proxy?.$modal.loading('正在上传文件,请稍候...');
const formData = new FormData();

View File

@ -185,6 +185,10 @@ const props = defineProps({
taskVariables: {
type: Object as () => Record<string, any>,
default: () => {}
},
businessId1: {
type: String,
default: ''
}
});
//遮罩层
@ -336,6 +340,9 @@ const handleCompleteTask = async () => {
}
if (isDrawing.value) {
isShowSubmit.value = true;
nextTick(() => {
detailFormTeRef.value.getInfo(props.businessId1);
});
return;
}
await proxy?.$modal.confirm('是否确认提交?');
@ -538,6 +545,9 @@ const handleTermination = async () => {
const handleTerminationTask = async () => {
if (isDrawing.value) {
isShowTermination.value = true;
nextTick(() => {
detailFormTeRef.value.getInfo(props.businessId);
});
return;
}
const params = {

View File

@ -1,5 +1,5 @@
<template>
<div class="select-container">
<div class="select-container" v-loading.fullscreen.lock="fullscreenLoading">
<label for="projectSelect" class="select-label">项目列表:</label>
<el-select
id="projectSelect"
@ -19,12 +19,18 @@
import { ref, computed, watch } from 'vue';
import { useUserStore } from '@/store/modules/user';
import { getProjectTeam } from '@/utils/projectTeam';
import router, { resetRouter } from '@/router';
import usePermissionStore from '@/store/modules/permission';
import { isHttp } from '@/utils/validate';
import { changeProject } from '@/api/project/project';
const fullscreenLoading = ref(false);
const route = useRoute();
const userStore = useUserStore();
const projects = computed(() => [
// { id: '', name: '全部工程项目' }, // 添加空选项
...userStore.projects
]);
const proxy = getCurrentInstance()?.proxy as any;
const selectedProjectId = ref(userStore.selectedProject?.id || '');
@ -37,13 +43,66 @@ watch(
{ deep: true }
);
const handleSelect = (projectId: string) => {
/** 切换项目逻辑 */
const handleSelect = async (projectId: string) => {
proxy.$cache.local.setJSON('isCheckRole', 'true');
const userStore = useUserStore();
const permissionStore = usePermissionStore();
const selectedProject = projects.value.find((p) => p.id === projectId);
if (selectedProject) {
userStore.setSelectedProject(selectedProject);
console.log(userStore.selectedProject); // 打印选中的项目
}
if (!selectedProject) return;
const loadingInstance = ElLoading.service({
lock: true,
text: '项目切换中...',
background: 'rgba(0, 0, 0, 0.7)'
});
setTimeout(() => {
if (loadingInstance && loadingInstance.visible) {
loadingInstance.close();
}
}, 3000);
await changeProject(projectId);
console.log('切换项目', selectedProject);
// 更新项目 & 权限
userStore.setSelectedProject(selectedProject);
await userStore.setInfo();
await userStore.setRoles(); // 这里会刷新 permissions/roles
// 重新生成路由
permissionStore.generateRoutes().then((routeList) => {
const currentPath = router.currentRoute.value.fullPath;
const exist = currentPath == '/' || currentPath == '/index' ? true : routeExists(currentPath, routeList);
if (exist) return loadingInstance.close();
proxy?.$tab.closeAllPage();
router.push('/index');
loadingInstance.close();
// 刷新当前路由
});
};
function routeExists(fullPath: string, routes: any[], parentPath = ''): boolean {
for (const route of routes) {
// 拼接完整 path
let currentPath = route.path.startsWith('/') ? route.path : `${parentPath}/${route.path}`;
// 处理多余的 "//"
currentPath = currentPath.replace(/\/+/g, '/');
// 判断
if (currentPath === fullPath) {
return true;
}
// 递归子路由
if (route.children && route.children.length > 0) {
if (routeExists(fullPath, route.children, currentPath)) {
return true;
}
}
}
return false;
}
</script>
<style lang="scss" scoped>

View File

@ -4,6 +4,7 @@
<el-menu-item v-if="index < visibleNumber" :key="index" :style="{ '--theme': theme }" :index="item.path">
<svg-icon v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" :icon-class="item.meta ? item.meta.icon : ''" />
{{ item.meta?.title }}
<!-- <span class="bage" v-if="item.meta?.title == '我的任务' && total > 0">{{ total }}</span> -->
</el-menu-item>
</template>
@ -26,20 +27,27 @@ import useAppStore from '@/store/modules/app';
import useSettingsStore from '@/store/modules/settings';
import usePermissionStore from '@/store/modules/permission';
import { RouteRecordRaw } from 'vue-router';
import useUserStore from '@/store/modules/user';
import useNoticeStore from '@/store/modules/notice';
import { pageByTaskWait } from '@/api/workflow/task';
const userStore = useUserStore();
const noticeStore = storeToRefs(useNoticeStore());
// 顶部栏初始数
const visibleNumber = ref<number>(-1);
// 当前激活菜单的 index
const currentIndex = ref<string>();
// 隐藏侧边栏路由
const hideList = ['/index', '/user/profile'];
const total = ref(1);
const appStore = useAppStore();
const settingsStore = useSettingsStore();
const permissionStore = usePermissionStore();
const route = useRoute();
const router = useRouter();
onMounted(() => {
console.log(33333);
getWaitingList();
});
// 主题颜色
const theme = computed(() => settingsStore.theme);
// 所有的路由信息
@ -158,6 +166,26 @@ onBeforeUnmount(() => {
onMounted(() => {
setVisibleNumber();
});
// 获取我的待办
//分页
const getWaitingList = () => {
pageByTaskWait({ pageNum: 1, pageSize: 10 }).then((resp) => {
console.log(resp);
total.value = resp.total;
});
};
//用深度监听 消息
watch(
() => noticeStore.state.value.notices,
(newVal) => {
let time = setTimeout(() => {
getWaitingList();
clearTimeout(time);
}, 500);
},
{ deep: true }
);
</script>
<style lang="scss">
@ -197,4 +225,31 @@ onMounted(() => {
.topmenu-container .svg-icon {
margin-right: 4px;
}
.bage {
position: absolute;
top: 6px;
right: -12px;
padding: 0 6px;
height: 16px;
line-height: 16px;
background: #ff7a7a;
border-radius: 8px;
font-size: 12px;
color: #fff;
white-space: nowrap;
box-sizing: border-box;
}
.el-menu-item .el-menu-item__content {
position: relative;
padding-right: 24px;
}
.menu-title {
display: inline-block;
max-width: calc(100% - 24px);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

View File

@ -23,7 +23,7 @@
<!-- <header-search id="header-search" class="right-menu-item" /> -->
<search-menu ref="searchMenuRef" />
<el-tooltip effect="dark" placement="bottom">
<el-tooltip effect="dark" placement="bottom">
<ProjectSelector />
</el-tooltip>
<!-- <el-tooltip content="搜索" effect="dark" placement="bottom">

View File

@ -6,6 +6,7 @@
<svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
<template #title>
<span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span>
<span class="bage" v-if="onlyOneChild.meta?.title == '我的待办' && total > 0">{{ total }}</span>
</template>
</el-menu-item>
</app-link>
@ -15,6 +16,7 @@
<template v-if="item.meta" #title>
<svg-icon :icon-class="item.meta ? item.meta.icon : ''" />
<span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
<!-- <span class="bage" v-if="item.meta?.title == '我的任务' && total >= 0">{{ total }}</span> -->
</template>
<sidebar-item
@ -34,7 +36,11 @@ import { isExternal } from '@/utils/validate';
import AppLink from './Link.vue';
import { getNormalPath } from '@/utils/ruoyi';
import { RouteRecordRaw } from 'vue-router';
import { pageByTaskWait } from '@/api/workflow/task';
import useUserStore from '@/store/modules/user';
import useNoticeStore from '@/store/modules/notice';
const userStore = useUserStore();
const noticeStore = storeToRefs(useNoticeStore());
const props = defineProps({
item: {
type: Object as PropType<RouteRecordRaw>,
@ -49,7 +55,22 @@ const props = defineProps({
default: ''
}
});
const total = ref(0);
onMounted(() => {
if (onlyOneChild.value.meta?.title == '我的待办' || props.item.meta?.title == '我的任务') {
console.log(44444444);
getWaitingList();
}
});
// 获取我的待办
//分页
const getWaitingList = () => {
pageByTaskWait({ pageNum: 1, pageSize: 10 }).then((resp) => {
console.log(resp);
total.value = resp.total;
});
};
const onlyOneChild = ref<any>({});
const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[]) => {
@ -64,12 +85,12 @@ const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[])
return true;
});
// When there is only one child router, the child router is displayed by default
// 只有一个子路由时默认显示子路由
if (showingChildren.length === 1) {
return true;
}
// Show parent if there are no child router to display
// 没有子路由可显示时显示父路由
if (showingChildren.length === 0) {
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true };
return true;
@ -98,4 +119,49 @@ const hasTitle = (title: string | undefined): string => {
}
return title;
};
//用深度监听 消息
watch(
() => noticeStore.state.value.notices,
(newVal) => {
if (onlyOneChild.value.meta?.title == '我的待办') {
console.log(121212121);
let time = setTimeout(() => {
getWaitingList();
clearTimeout(time);
}, 500);
}
},
{ deep: true }
);
</script>
<style lang="scss" scoped>
.bage {
position: absolute;
top: 6px;
right: 36px;
padding: 0 6px;
height: 16px;
line-height: 16px;
background: #ff7a7a;
border-radius: 8px;
font-size: 12px;
color: #fff;
white-space: nowrap;
box-sizing: border-box;
}
.el-menu-item .el-menu-item__content {
position: relative;
padding-right: 24px;
}
.menu-title {
display: inline-block;
max-width: calc(100% - 24px);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

View File

@ -51,11 +51,12 @@ const getTableData = async () => {
//点击消息,写入已读
const onNewsClick = (item: any) => {
newsList.value[item].read = true;
console.log('🚀 ~ onNewsClick ~ newsList.value[item]:', newsList.value[item]);
//并且写入pinia
noticeStore.state.value.notices = newsList.value;
//如果有formPath就前往
if (newsList.value[item].route) {
proxy?.$tab.openPage('/' + newsList.value[item].route, '', { id: newsList.value[item].detailId, type: 'view' });
proxy?.$tab.openPage(newsList.value[item].route, '', { id: newsList.value[item].detailId, type: 'view' });
}
};

View File

@ -1,3 +1,4 @@
import $cache from '@/plugins/cache';
import { to as tos } from 'await-to-js';
import router from './router';
import NProgress from 'nprogress';
@ -9,6 +10,8 @@ import useUserStore from '@/store/modules/user';
import useSettingsStore from '@/store/modules/settings';
import usePermissionStore from '@/store/modules/permission';
let isFirst = false;
NProgress.configure({ showSpinner: false });
const whiteList = ['/login', '/register', '/social-callback', '/register*', '/register/*', '/materials/purchaseDoc/uploadCode'];
@ -16,54 +19,64 @@ const isWhiteList = (path: string) => {
return whiteList.some((pattern) => isPathMatch(pattern, path));
};
router.beforeEach(async (to, from, next) => {
router.beforeEach(async (to, from) => {
NProgress.start();
if (to.path == '/indexEquipment' || to.path == '/materials/purchaseDoc/uploadCode' || to.path == '/codeDetail') {
next();
} else if (getToken()) {
to.meta.title && useSettingsStore().setTitle(to.meta.title);
/* has token*/
if (to.path === '/login') {
next({ path: '/' });
NProgress.done();
} else if (isWhiteList(to.path)) {
next();
} else {
if (useUserStore().roles.length === 0) {
isRelogin.show = true;
// 判断当前用户是否已拉取完user_info信息
const [err] = await tos(useUserStore().getInfo());
if (err) {
await useUserStore().logout();
ElMessage.error(err);
next({ path: '/' });
} else {
isRelogin.show = false;
const accessRoutes = await usePermissionStore().generateRoutes();
// 根据roles权限生成可访问的路由表
accessRoutes.forEach((route) => {
if (!isHttp(route.path)) {
router.addRoute(route); // 动态添加可访问路由表
}
});
// @ts-expect-error hack方法 确保addRoutes已完成
next({ path: to.path, replace: true, params: to.params, query: to.query, hash: to.hash, name: to.name as string }); // hack方法 确保addRoutes已完成
}
} else {
next();
}
}
} else {
// 没有token
if (isWhiteList(to.path)) {
// 在免登录白名单,直接进入
next();
} else {
const redirect = encodeURIComponent(to.fullPath || '/');
next(`/login?redirect=${redirect}`); // 否则全部重定向到登录页
NProgress.done();
}
// 特殊页面放行
if (['/indexEquipment', '/materials/purchaseDoc/uploadCode', '/codeDetail'].includes(to.path)) {
return true;
}
// 已登录
if (getToken()) {
if (to.meta.title) useSettingsStore().setTitle(to.meta.title);
if (to.path === '/login') {
NProgress.done();
return { path: '/' };
}
if (isWhiteList(to.path)) {
return true;
}
if ((!isFirst && useUserStore().roles.length === 0) || $cache.local.getJSON('isCheckRole') === 'true') {
isFirst = true;
isRelogin.show = true;
const [err] = await tos(useUserStore().getInfo());
if (err) {
await useUserStore().logout();
ElMessage.error(err);
NProgress.done();
return { path: '/' };
}
isRelogin.show = false;
const accessRoutes = await usePermissionStore().generateRoutes();
accessRoutes.forEach((route) => {
if (!isHttp(route.path)) router.addRoute(route);
});
$cache.local.remove('isCheckRole');
// 确保路由已添加后再跳转
return { ...to, replace: true };
}
return true;
} else {
isFirst = false;
}
// 未登录
if (isWhiteList(to.path)) {
return true;
}
const redirect = encodeURIComponent(to.fullPath || '/');
NProgress.done();
return { path: `/login?redirect=${redirect}` };
});
router.afterEach(() => {

View File

@ -1,6 +1,7 @@
import { createWebHistory, createRouter, RouteRecordRaw } from 'vue-router';
/* Layout */
import Layout from '@/layout/index.vue';
import usePermissionStore from '@/store/modules/permission';
/**
* Note: 路由配置项
@ -65,11 +66,7 @@ export const constantRoutes: RouteRecordRaw[] = [
component: () => import('@/views/register.vue'),
hidden: true
},
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/error/404.vue'),
hidden: true
},
{
path: '/401',
component: () => import('@/views/error/401.vue'),
@ -134,10 +131,16 @@ export const constantRoutes: RouteRecordRaw[] = [
component: () => import('@/views/gis2D/index.vue'),
hidden: true
},
{
path: '/materials/purchaseDoc/uploadCode',
component: () => import('@/views/materials/purchaseDoc/uploadCode.vue'),
hidden: true
},
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/error/404.vue'),
hidden: true
}
];
@ -231,3 +234,11 @@ const router = createRouter({
});
export default router;
export function resetRouter() {
router.getRoutes().forEach((route) => {
if (route.name && !constantRoutes.find((r) => r.name === route.name)) {
router.hasRoute(route.name) && router.removeRoute(route.name);
}
});
}

View File

@ -10,6 +10,7 @@ import ParentView from '@/components/ParentView/index.vue';
import InnerLink from '@/layout/components/InnerLink/index.vue';
import { createCustomNameComponent } from '@/utils/createCustomNameComponent';
import { useUserStoreHook } from './user';
// 匹配views里面所有的.vue文件
const modules = import.meta.glob('./../../views/**/*.vue');
@ -44,7 +45,7 @@ export const usePermissionStore = defineStore('permission', () => {
sidebarRouters.value = routes;
};
const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
const res = await getRouters();
const res = await getRouters(useUserStoreHook().selectedProject?.id || '0');
const { data } = res;
const sdata = JSON.parse(JSON.stringify(data));
const rdata = JSON.parse(JSON.stringify(data));

View File

@ -28,7 +28,6 @@ const getSelectedProjectFromStorage = () => {
const getProjectTeamListFromStorage = () => {
const stored = $cache.local.getJSON('ProjectTeamList');
console.log('获取缓存的项目班组列表:', stored);
return stored ? stored : null;
};
@ -41,7 +40,9 @@ export const useUserStore = defineStore('user', () => {
const deptId = ref<string | number>('');
const avatar = ref('');
const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限
const permissions = ref<Array<string>>([]); // 用户权限编码集合 → 判断按钮权限
const permissions = ref<Array<any>>([]); // 用户权限编码集合 → 判断按钮权限
const permissionList = ref<Array<any>>([]); // 用户所有权限列表
const roleList = ref<Array<any>>([]); // 用户所有角色列表
const projects = ref<Array<{ id: string; name: string }>>([]);
// 从localStorage获取缓存的项目如果没有则默认为null
@ -66,15 +67,32 @@ export const useUserStore = defineStore('user', () => {
// 获取用户信息
const getInfo = async (): Promise<void> => {
// **新增项目数据获取**
const [projectErr, projectRes] = await to(getUserProject());
if (projectRes?.data) {
const projectList = projectRes.data.map((p) => ({
id: p.projectId,
name: p.projectName || '未知项目'
}));
setProjects(projectList);
// 如果有缓存的选中项目,且该项目在当前项目列表中存在,则使用缓存的项目
const storedProject = getSelectedProjectFromStorage();
if (storedProject && projectList.some((p) => p.id === storedProject.id)) {
setSelectedProject(storedProject);
} else if (projectList.length > 0) {
// 否则默认选择第一个项目
setSelectedProject(projectList[0]);
}
}
const [err, res] = await to(getUserInfo());
if (res) {
const data = res.data;
const user = data.user;
const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar;
if (data.roles && data.roles.length > 0) {
roles.value = data.roles;
permissions.value = data.permissions;
permissionList.value = data.permissions;
roleList.value = data.roles;
setRoles();
} else {
roles.value = ['ROLE_DEFAULT'];
}
@ -85,30 +103,38 @@ export const useUserStore = defineStore('user', () => {
tenantId.value = user.tenantId;
deptId.value = user.deptId;
// **新增项目数据获取**
const [projectErr, projectRes] = await to(getUserProject());
if (projectRes?.data) {
const projectList = projectRes.data.map((p) => ({
id: p.projectId,
name: p.projectName || '未知项目'
}));
setProjects(projectList);
// 如果有缓存的选中项目,且该项目在当前项目列表中存在,则使用缓存的项目
const storedProject = getSelectedProjectFromStorage();
if (storedProject && projectList.some((p) => p.id === storedProject.id)) {
setSelectedProject(storedProject);
} else if (projectList.length > 0) {
// 否则默认选择第一个项目
setSelectedProject(projectList[0]);
}
}
return Promise.resolve();
}
return Promise.reject(err);
};
const setInfo = async () => {
const [err, res] = await to(getUserInfo());
if (res) {
const data = res.data;
const user = data.user;
const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar;
if (data.roles && data.roles.length > 0) {
permissionList.value = data.permissions;
roleList.value = data.roles;
setRoles();
} else {
roles.value = ['ROLE_DEFAULT'];
}
name.value = user.userName;
nickname.value = user.nickName;
avatar.value = profile;
userId.value = user.userId;
tenantId.value = user.tenantId;
deptId.value = user.deptId;
}
};
const setRoles = () => {
const projectRole = roleList.value.find((item) => item.projectId == selectedProject.value?.id)?.projectRoles || [];
roles.value = projectRole;
const projectPermissions = permissionList.value.find((item) => item.projectId == selectedProject.value?.id)?.projectPermissions || [];
permissions.value = projectPermissions;
};
// 注销
const logout = async (): Promise<void> => {
@ -158,7 +184,9 @@ export const useUserStore = defineStore('user', () => {
setProjectTeamList,
projects,
selectedProject,
ProjectTeamList
ProjectTeamList,
setInfo,
setRoles
};
});

View File

@ -20,7 +20,6 @@ export const initSSE = (url: any) => {
});
watch(error, () => {
console.log('SSE connection error:', error.value);
error.value = null;
});
@ -31,9 +30,12 @@ export const initSSE = (url: any) => {
try {
if (JSON.parse(data.value)) {
const obj = JSON.parse(data.value);
route1 = obj.route;
label = obj.message;
detailId = obj.detailId;
route1 = obj.type;
if (obj.type == 'count') {
return;
}
label = obj.content;
// detailId = obj.detailId;
data.value = null;
}
} catch (error) {

View File

@ -10,12 +10,11 @@
@click="isDisabled = false"
class="px-8 py-2.5 transition-all duration-300 font-medium"
v-if="isDisabled"
v-hasPermi="['cailiaoshebei:purchaseUser:addOrUpdate']"
v-hasPermi="['bidding:biddingUser:add']"
>
点击编辑
</el-button>
</div>
<!-- 表单内容区域 -->
<el-form ref="leaveFormRef" :model="form" :rules="rules" label-width="120px" class="p-6 pt30 space-y-6 h75" :disabled="isDisabled">
<!-- 设计负责人 -->
@ -30,7 +29,6 @@
</el-select>
</el-form-item>
</div>
<!-- 提交按钮区域 -->
<div class="flex justify-center space-x-6 mt-8 pt-6 border-t border-gray-100" v-if="!isDisabled">
<el-button
@ -38,7 +36,7 @@
@click="submitForm"
icon="Check"
class="px-8 py-2.5 transition-all duration-300 transform hover:scale-105 bg-blue-500 hover:bg-blue-600 text-white font-medium"
v-hasPermi="['cailiaoshebei:purchaseUser:addOrUpdate']"
v-hasPermi="['bidding:biddingUser:add']"
>
确认提交
</el-button>
@ -53,22 +51,14 @@
<script setup name="PersonnelForm" lang="ts">
import { ref, reactive, computed, onMounted, toRefs } from 'vue';
import { getCurrentInstance } from 'vue';
import type { ComponentInternalInstance } from 'vue';
import { useUserStoreHook } from '@/store/modules/user';
import { ElMessage, ElLoading } from 'element-plus';
import { biddingGetUser, AddbiddingUser, biddingUserList } from '@/api/bidding/appointment';
import { getProject } from '@/api/project/project';
// 获取当前实例
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 获取用户 store
const userStore = useUserStoreHook();
// 从 store 中获取当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
// 专业字典数据
const { des_user_major } = toRefs<any>(proxy?.useDict('des_user_major'));
const isDisabled = ref(false);
const projectInfo = ref({}); //项目信息
// 表单数据
const form = reactive({
id: null,

View File

@ -63,14 +63,7 @@
<el-table-column prop="quantity" label="数量" />
<el-table-column prop="remark" label="单价" align="center">
<template #default="scope">
<el-input-number
:model-value="scope.row.unitPrice"
@change="(val) => (scope.row.unitPrice = val)"
:precision="2"
:step="0.1"
:controls="false"
v-if="scope.row.quantity && scope.row.quantity != 0"
/>
<span>{{ scope.row.unitPrice }}</span>
</template>
</el-table-column>
<el-table-column prop="price" label="总价" align="center">

View File

@ -19,13 +19,35 @@
<h3 class="text-lg font-semibold text-gray-800">成本核算清单</h3>
</div>
<div class="p-6">
<el-form ref="leaveFormRef" disabled :model="form" :rules="rules" label-width="100px" class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4" v-for="item in sheets" :key="item">
<el-form-item label="表格文件">
<span style="color: #8d8d8d">{{ item }}</span>
</el-form-item>
<el-form ref="leaveFormRef" v-loading="loading" :model="form" :rules="rules" label-width="100px" class="space-y-4">
<div class="grid grid-cols-1 gap-4">
<el-row>
<el-col :span="12">
<el-form-item label="版本号" prop="formNo">
<el-input :disabled="true" v-model="form.versions" placeholder="请输入文件名称" />
</el-form-item>
<el-form-item label="表名" prop="sheet">
<el-select v-model="form.sheet" placeholder="选择表名" @change="changeSheet">
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
<el-table :data="tableData" style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)" row-key="id" default-expand-all border>
<el-table-column prop="num" label="编号" />
<el-table-column prop="name" label="名称" />
<el-table-column prop="specification" label="规格" />
<el-table-column prop="unit" label="单位" />
<el-table-column prop="quantity" label="数量" />
<el-table-column prop="unitPrice" label="单价" align="center" />
<el-table-column prop="price" label="总价" align="center">
<template #default="scope">
{{ scope.row.price != 0 ? Number(scope.row.price).toFixed(2) : null }}
</template>
</el-table-column>
</el-table>
</div>
</el-card>
<!-- 提交组件 -->
@ -68,9 +90,9 @@ import SubmitVerify from '@/components/Process/submitVerify.vue';
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
import ApprovalButton from '@/components/Process/approvalButton.vue';
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { proxy } = getCurrentInstance() as any;
import { useUserStoreHook } from '@/store/modules/user';
import { getVersionDetail, sheetList } from '@/api/bidding/biddingLimit';
import { getVersionDetail, sheetList, getTreeLimit } from '@/api/bidding/biddingLimit';
// 获取用户 store
const userStore = useUserStoreHook();
@ -99,7 +121,6 @@ const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
//按钮组件
const approvalButtonRef = ref<InstanceType<typeof ApprovalButton>>();
const sheets = ref([]);
const versions = ref({});
const leaveFormRef = ref<ElFormInstance>();
const dialog = reactive({
@ -124,7 +145,10 @@ const initFormData = {
fileSuffix: undefined,
originalName: undefined,
remark: undefined,
fileId: undefined
fileId: undefined,
status: undefined,
versions: undefined,
sheet: undefined
};
const data = reactive({
form: { ...initFormData },
@ -150,24 +174,46 @@ const getInfo = () => {
buttonLoading.value = false;
nextTick(async () => {
const res = await getVersionDetail(routeParams.value.id);
console.log(res);
Object.assign(form.value, res.data);
getSheetName(res.data.versions);
loading.value = false;
buttonLoading.value = false;
getSheetName();
});
};
const sheets = ref([]);
//获取表名
const getSheetName = async (versions) => {
const params = {
projectId: currentProject.value?.id,
versions
};
const res = await sheetList(params);
if (res.code == 200) {
sheets.value = res.data;
if (res.data.length > 0) {
const getSheetName = async () => {
try {
const params = {
projectId: currentProject.value?.id,
versions: form.value.versions
};
const res = await sheetList(params);
if (res.code == 200) {
sheets.value = res.data;
if (res.data.length > 0) {
form.value.sheet = res.data[0];
}
getListTable();
}
} catch (error) {}
};
//选择表名
const changeSheet = () => {
getListTable();
};
const tableData = ref([]);
//获取列表
const getListTable = async () => {
const res = await getTreeLimit({
projectId: currentProject.value?.id,
versions: form.value.versions,
sheet: form.value.sheet
});
if (res.code == 200) {
tableData.value = res.data;
}
};
/** 提交按钮 */
@ -185,7 +231,7 @@ const submitFlow = async () => {
const handleStartWorkFlow = async (data: LeaveForm) => {
try {
submitFormData.value.flowCode = flowCode.value;
submitFormData.value.businessId = data.versions + '_abc';
submitFormData.value.businessId = data.id;
//流程变量
taskVariables.value = {
// leave4/5 使用的流程变量
@ -203,7 +249,7 @@ const handleStartWorkFlow = async (data: LeaveForm) => {
};
//审批记录
const handleApprovalRecord = () => {
approvalRecordRef.value.init(form.value.versions + '_abc');
approvalRecordRef.value.init(form.value.id);
};
//提交回调
const submitCallback = async () => {
@ -242,9 +288,10 @@ onMounted(() => {
reset();
routeParams.value = proxy.$route.query;
loading.value = false;
// if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
getInfo();
// }
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
getInfo();
console.log('routeParams.value', routeParams.value);
}
});
});
</script>

View File

@ -1,8 +1,7 @@
<template>
<div class="p-4 bg-gray-50 min-h-screen">
<!-- 卡片容器控制最大宽度+居中+圆角阴影 -->
<el-card shadow="hover" class="max-w-6xl mx-auto rounded-xl overflow-hidden border-0"
style="background-color: #ffffff">
<el-card shadow="hover" class="max-w-6xl mx-auto rounded-xl overflow-hidden border-0" style="background-color: #ffffff">
<!-- 卡片头部项目信息展示区 -->
<template #header>
<div class="bg-blue-50 px-6 rounded-t-xl" style="padding: 10px 20px">
@ -64,8 +63,15 @@
</div> -->
</template>
<!-- 中标信息表单区域 -->
<el-form :disabled="isDisabled" ref="listOfWinningBidsFormRef" :model="form" :rules="rules" label-width="150px"
class="p-6 pt-4" style="background-color: #ffffff">
<el-form
:disabled="isDisabled"
ref="listOfWinningBidsFormRef"
:model="form"
:rules="rules"
label-width="150px"
class="p-6 pt-4"
style="background-color: #ffffff"
>
<el-row :gutter="32">
<!-- 招标代理机构 -->
<el-col :span="12">
@ -82,15 +88,25 @@
<!-- 投标截止时间 -->
<el-col :span="12">
<el-form-item label="投标截止时间" prop="biddingDeadline" class="rounded-lg border border-gray-100 p-1 mb-5">
<el-date-picker v-model="form.biddingDeadline" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" type="datetime" placeholder="请选择投标截止时间" />
<el-date-picker
v-model="form.biddingDeadline"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
type="datetime"
placeholder="请选择投标截止时间"
/>
</el-form-item>
</el-col>
<!-- 开标时间 -->
<el-col :span="12">
<el-form-item label="开标时间" prop="bidopeningTime" class="rounded-lg border border-gray-100 p-1 mb-5">
<el-date-picker v-model="form.bidopeningTime" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" type="datetime" placeholder="请选择开标时间" />
<el-date-picker
v-model="form.bidopeningTime"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
type="datetime"
placeholder="请选择开标时间"
/>
</el-form-item>
</el-col>
@ -108,17 +124,26 @@
</el-col>
<!-- 答疑截止时间 -->
<el-col :span="12">
<el-form-item label="答疑截止时间" prop="answeringDeadlineTime"
class="rounded-lg border border-gray-100 p-1 mb-5">
<el-date-picker v-model="form.answeringDeadlineTime" type="datetime" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择答疑截止时间" />
<el-form-item label="答疑截止时间" prop="answeringDeadlineTime" class="rounded-lg border border-gray-100 p-1 mb-5">
<el-date-picker
v-model="form.answeringDeadlineTime"
type="datetime"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择答疑截止时间"
/>
</el-form-item>
</el-col>
<!-- 澄清截止时间 -->
<el-col :span="12">
<el-form-item label="澄清截止时间" prop="clarifyDeadlineTime" class="rounded-lg border border-gray-100 p-1 mb-5">
<el-date-picker format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss "
v-model="form.clarifyDeadlineTime" type="datetime" placeholder="请选择澄清截止时间" />
<el-date-picker
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss "
v-model="form.clarifyDeadlineTime"
type="datetime"
placeholder="请选择澄清截止时间"
/>
</el-form-item>
</el-col>
<!-- 项目概况 -->
@ -131,22 +156,31 @@
<!-- 操作按钮区域 -->
<el-row v-if="!form.id" class="mt-4">
<el-col :span="24" class="text-center">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"
v-hasPermi="['bidding:listOfWinningBids:add', 'bidding:listOfWinningBids:edit']" class="rounded-full px-8"
size="large">
<el-button
:loading="buttonLoading"
type="primary"
@click="submitForm"
v-hasPermi="['bidding:listOfWinningBids:add', 'bidding:listOfWinningBids:edit']"
class="rounded-full px-8"
size="large"
>
确认提交
</el-button>
<el-button type="default" @click="resetForm" class="ml-6 rounded-full px-8" size="large"> 重置 </el-button>
</el-col>
</el-row>
</el-form>
<div style="margin-top: 20px;" v-if="form.id">
<span style=" color: rgb(38 153 255);
display: inline-block;
margin-left: 40px;
font-weight: 700;">是否中标配置</span>
<el-form ref="listOfWinningBidsFormRef" :disabled="iswhetherBid" :model="form" :rules="rules"
label-width="150px" class="p-6 pt-4" style="background-color: #ffffff">
<div style="margin-top: 20px" v-if="form.id">
<span style="color: rgb(38 153 255); display: inline-block; margin-left: 40px; font-weight: 700">是否中标配置</span>
<el-form
ref="listOfWinningBidsFormRef"
:disabled="iswhetherBid"
:model="form"
:rules="rules"
label-width="150px"
class="p-6 pt-4"
style="background-color: #ffffff"
>
<el-row>
<!-- 是否中标必填 -->
<el-col :span="12">
@ -174,9 +208,14 @@
<!-- 操作按钮区域 -->
<el-row class="mt-4" v-if="!iswhetherBid && form.whetherBid == '0'">
<el-col :span="24" class="text-center">
<el-button :loading="buttonLoading1" type="primary" @click="submitForm"
<el-button
:loading="buttonLoading1"
type="primary"
@click="submitForm"
v-hasPermi="['bidding:listOfWinningBids:add', 'bidding:listOfWinningBids:edit']"
class="rounded-full px-8" size="large">
class="rounded-full px-8"
size="large"
>
中标
</el-button>
</el-col>
@ -205,10 +244,6 @@ const fileList = ref([]);
const userStore = useUserStoreHook();
const iswhetherBid = ref(false); // 是否中标
const currentProject = computed(() => userStore.selectedProject);
// const realUploadUrl = computed(() => {
// const search = new URLSearchParams().toString();
// return search ? `${baseUrl}${props.uploadUrl}?${search}` : `${baseUrl}${props.uploadUrl}`;
// });
// 项目信息(仅展示,非表单编辑)
const projectInfo = reactive({
principal: undefined,
@ -323,14 +358,7 @@ const getDictLabel = (dictList: any[], value: any) => {
const dictItem = dictList.find((item) => item.value === value);
return dictItem ? dictItem.label : '';
};
const upload = ref<UploadInstance>();
const handleExceed: UploadProps['onExceed'] = (files) => {
upload.value!.clearFiles();
const file = files[0] as UploadRawFile;
file.uid = genFileId();
upload.value!.handleStart(file);
};
/**
* 初始化中标数据根据项目ID查询已有记录
*/

View File

@ -38,17 +38,17 @@
v-if="versionObj.status == 'draft'"
icon="Edit"
@click="handleAudit"
v-hasPermi="['desibiddinggn:biddingLimitList:query']"
v-hasPermi="['bidding:biddingLimitList:getVersionDetail']"
>审核</el-button
>
</el-form-item>
<el-form-item>
<el-button
type="primary"
type="warning"
icon="view"
@click="handleViewInfo"
v-hasPermi="['desibiddinggn:biddingLimitList:query']"
v-if="versionObj.status != 'draft'"
v-hasPermi="['bidding:biddingLimitList:getVersionDetail']"
v-if="versionObj.status && versionObj.status != 'draft'"
>查看流程</el-button
>
</el-form-item>
@ -60,13 +60,22 @@
<el-table-column prop="num" label="编号" />
<el-table-column prop="name" label="工程或费用名称" />
<el-table-column prop="unit" label="单位" />
<el-table-column prop="quantity" label="数量" />
<el-table-column prop="quantity" label="数量">
<template #default="scope">
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
</template>
</el-table-column>
<el-table-column prop="remark" label="单价" align="center">
<template #default="scope">
<el-input-number
:disabled="versionObj.status != 'draft'"
:model-value="scope.row.unitPrice"
@change="(val) => (scope.row.unitPrice = val)"
@change="
(val) => {
scope.row.unitPrice = val;
changePrice(scope.row);
}
"
:precision="2"
:step="0.1"
:controls="false"
@ -76,16 +85,16 @@
</el-table-column>
<el-table-column prop="price" label="总价" align="center">
<template #default="scope">
{{ scope.row.price }}
{{ scope.row.price != 0 ? Number(scope.row.price).toFixed(2) : null }}
</template>
</el-table-column>
<el-table-column prop="price" label="操作" align="center">
<el-table-column prop="operate" label="操作" align="center">
<template #default="scope">
<el-button
type="primary"
size="small"
:disabled="versionObj.status != 'draft'"
@click="handleSave(scope.row)"
@click="handleSave(scope.row, 'all')"
v-if="scope.row.quantity && scope.row.quantity != 0"
v-hasPermi="['bidding:biddingLimitList:edit']"
>确定</el-button
@ -174,7 +183,8 @@ const getTableData = async () => {
loading.value = true;
const params = {
projectId: currentProject.value?.id,
sheet: queryForm.value.sheet
sheet: queryForm.value.sheet,
versions: queryForm.value.versions
};
const res = await getTreeLimit(params);
loading.value = false;
@ -186,31 +196,53 @@ const getTableData = async () => {
}
}
};
//修改单价
const handleSave = (row: any) => {
const modifyPrice = new Map();
const changePrice = (row: any) => {
modifyPrice.set(row.id, row);
// if (!row.unitPrice) {
// modifyPrice.delete(row.id);
// }
};
//修改单价 biddingLimitListUpdate
const handleSave = (row?: any, type?: any) => {
try {
if (!row.unitPrice) {
ElMessage({
message: '请输入单价',
type: 'warning'
if (type == 'single') {
loading.value = true;
const list = [{ ...row }];
biddingLimitListUpdate(list).then((res) => {
if (res.code == 200) {
ElMessage({
message: '修改成功',
type: 'success'
});
getTableData();
}
});
}
if (type == 'all') {
loading.value = true;
const list = [];
modifyPrice.forEach((item) => {
list.push({ ...item });
});
biddingLimitListUpdate(list).then((res) => {
if (res.code == 200) {
ElMessage({
message: '修改成功',
type: 'success'
});
getTableData();
}
});
return;
}
loading.value = true;
biddingLimitListUpdate(row).then((res) => {
if (res.code == 200) {
ElMessage({
message: '修改成功',
type: 'success'
});
getTableData();
}
});
} catch (error) {
ElMessage({
message: '修改失败',
type: 'error'
});
} finally {
loading.value = false;
}
};
const tableRef = ref<any>();
@ -267,7 +299,7 @@ const handleAudit = () => {
path: `/approval/biddingLimit/indexEdit`,
query: {
id,
type: 'add',
type: 'update',
sheets: sheets.value,
versions: versionObj.value
}

View File

@ -26,20 +26,39 @@
<el-table-column prop="name" label="名称" />
<el-table-column prop="content" label="内容" />
<el-table-column prop="price" label="限价" />
<el-table-column prop="plannedBiddingTime" label="计划招标时间" align="center">
<el-table-column prop="plannedBiddingTime" align="center">
<template #header> <span style="color: red">*</span>计划招标时间 </template>
<template #default="scope">
<el-date-picker v-model="scope.row.plannedBiddingTime" type="date" value-format="YYYY-MM-DD" placeholder="选择时间" />
</template>
</el-table-column>
<el-table-column prop="price" label="操作" align="center">
<template #default="scope">
<el-button type="warning" size="small" @click="handleDetail(scope.row)" v-hasPermi="['tender:segmentedIndicatorPlanning:getMore']"
<el-button
type="warning"
icon="view"
size="small"
link
@click="handleDetail(scope.row)"
v-hasPermi="['tender:segmentedIndicatorPlanning:getMore']"
>详情</el-button
>
<el-button type="primary" size="small" @click="handleSave(scope.row)" v-hasPermi="['tender:segmentedIndicatorPlanning:edit']"
<el-button
type="primary"
icon="edit"
size="small"
link
@click="handleSave(scope.row)"
v-hasPermi="['tender:segmentedIndicatorPlanning:edit']"
>确定</el-button
>
<el-button type="danger" size="small" @click="delHandle(scope.row)" v-hasPermi="['tender:segmentedIndicatorPlanning:remove']"
<el-button
type="danger"
icon="delete"
size="small"
link
@click="delHandle(scope.row)"
v-hasPermi="['tender:segmentedIndicatorPlanning:remove']"
>删除</el-button
>
</template>
@ -99,7 +118,8 @@
<el-table-column prop="name" label="工程或费用名称" />
<el-table-column prop="unit" label="单位" />
<!-- <el-table-column prop="quantity" label="数量" /> -->
<el-table-column prop="selectNum" label="选择数量" align="center">
<el-table-column prop="quantity" label="计划量" align="center" />
<el-table-column prop="selectNum" label="设计量" align="center">
<template #default="scope">
<el-input-number
:model-value="scope.row.selectNum"
@ -113,16 +133,36 @@
:step="1"
:controls="false"
:max="Math.floor(scope.row.quantity)"
v-if="scope.row.quantity && scope.row.quantity != 0"
v-if="scope.row.quantity && scope.row.quantity != 0 && scope.row.unitPrice"
/>
</template>
</el-table-column>
<el-table-column prop="unitPrice" label="单价" align="center" />
<!-- <el-table-column prop="price" label="总价" align="center">
<el-table-column prop="useQuantity" label="剩余量" align="center">
<template #default="scope">
{{ scope.row.price }}
{{
(scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) == 0
? ''
: (scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
}}
</template>
</el-table-column> -->
</el-table-column>
<el-table-column prop="unitPrice" label="单价" align="center" />
<el-table-column prop="price" label="总价" align="center">
<template #default="scope">
{{
((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) *
Number(scope.row.unitPrice) ==
0
? ''
: (
((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) *
Number(scope.row.unitPrice)
).toFixed(2)
}}
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>

View File

@ -35,11 +35,19 @@
<el-form-item>
<el-button type="primary" @click="handleExport()" v-hasPermi="['tender:billofquantitiesLimitList:export']">导出excel</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" v-if="reviewStatus == 'draft'" @click="clickApprovalSheet()">审核</el-button>
<el-button type="primary" v-if="reviewStatus && reviewStatus == 'draft'" @click="clickApprovalSheet()">审核</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" v-if="reviewStatus != 'draft'" @click="clickApprovalSheet()">查看流程</el-button>
<el-button
type="warning"
icon="view"
v-if="reviewStatus && reviewStatus != 'draft'"
@click="clickApprovalSheet()"
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
>查看流程</el-button
>
</el-form-item>
</el-form>
</el-card>
@ -49,13 +57,22 @@
<el-table-column prop="num" label="编号" />
<el-table-column prop="name" label="工程或费用名称" />
<el-table-column prop="unit" label="单位" />
<el-table-column prop="quantity" label="数量" />
<el-table-column prop="quantity" label="数量">
<template #default="scope">
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
</template>
</el-table-column>
<el-table-column prop="unitPrice" label="单价" align="center">
<template #default="scope">
<el-input-number
:disabled="reviewStatus != 'draft'"
:model-value="scope.row.unitPrice"
@change="(val) => (scope.row.unitPrice = val)"
@change="
(val) => {
scope.row.unitPrice = val;
changePrice(scope.row);
}
"
:precision="2"
:step="0.1"
:controls="false"
@ -65,16 +82,18 @@
</el-table-column>
<el-table-column prop="price" label="总价" align="center">
<template #default="scope">
{{ scope.row.price }}
<!-- {{ scope.row.children.length > 0 ? scope.row.children.reduce((sum, child) => sum + child.price, 0) : scope.row.price }} -->
{{ scope.row.price != 0 ? Number(scope.row.price).toFixed(2) : null }}
<!-- {{ scope.row.price }} -->
</template>
</el-table-column>
<el-table-column prop="price" label="操作" align="center">
<el-table-column prop="operate" label="操作" align="center">
<template #default="scope">
<el-button
type="primary"
size="small"
:disabled="reviewStatus != 'draft'"
@click="handleSave(scope.row)"
@click="handleSave(scope.row, 'all')"
v-if="scope.row.quantity && scope.row.quantity != 0"
v-hasPermi="['tender:billofquantitiesLimitList:edit']"
>确定</el-button
@ -103,7 +122,8 @@ const sheets = ref<any[]>([]);
const tableData = ref<any[]>([]);
const isExpandAll = ref(false);
const reviewStatus = ref('');
const versionObj: any = ref({});
const versionMap = new Map();
//获取版本号
const getVersionNums = async () => {
try {
@ -118,9 +138,11 @@ const getVersionNums = async () => {
if (res.code == 200) {
options.value = res.data;
if (res.data.length > 0) {
res.data.forEach((item: any) => {
versionMap.set(item.versions, item);
});
queryForm.value.versions = res.data[0].versions;
reviewStatus.value = res.data[0].status;
getSheetName();
} else {
queryForm.value.versions = '';
@ -204,31 +226,50 @@ const getTableData = async () => {
loading.value = false;
}
};
const modifyPrice = new Map();
const changePrice = (row: any) => {
modifyPrice.set(row.id, row);
};
//修改单价
const handleSave = (row: any) => {
const handleSave = (row?: any, type?: any) => {
try {
if (!row.unitPrice) {
ElMessage({
message: '请输入单价',
type: 'warning'
if (type == 'single') {
loading.value = true;
const list = [{ ...row, type: '1' }];
updatePrice(list).then((res) => {
if (res.code == 200) {
ElMessage({
message: '修改成功',
type: 'success'
});
getTableData();
}
});
}
if (type == 'all') {
loading.value = true;
const list = [];
modifyPrice.forEach((item) => {
list.push({ ...item, type: '1' });
});
updatePrice(list).then((res) => {
if (res.code == 200) {
ElMessage({
message: '修改成功',
type: 'success'
});
getTableData();
}
});
return;
}
loading.value = true;
updatePrice({ ...row, type: '1' }).then((res) => {
if (res.code == 200) {
ElMessage({
message: '修改成功',
type: 'success'
});
getTableData();
}
});
} catch (error) {
ElMessage({
message: '修改失败',
type: 'error'
});
} finally {
loading.value = false;
}
};
const tableRef = ref<any>();
@ -283,20 +324,19 @@ const handleExport = () => {
// 审批
const clickApprovalSheet = () => {
proxy.$tab.closePage(proxy?.$route);
let id = versionMap.get(queryForm.value.versions).id;
proxy?.$router.push({
path: `/approval/contractLimitPrice/indexEdit`,
query: {
projectId: currentProject.value?.id,
versions: queryForm.value.versions,
sheet: queryForm.value.sheet,
id: id,
type: 'update',
status: reviewStatus.value
sheets: queryForm.value.sheet
}
});
};
onUnmounted(() => {
listeningProject();
console.log(11111111);
// console.log(11111111);
});
onMounted(() => {
getVersionNums();

View File

@ -16,26 +16,20 @@
<!-- 表单区域 -->
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
<h3 class="text-lg font-semibold text-gray-800">限价审核</h3>
<h3 class="text-lg font-semibold text-gray-800">限价审核</h3>
</div>
<div class="p-6">
<el-form
ref="leaveFormRef"
v-loading="loading"
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
:model="form"
:rules="rules"
label-width="100px"
class="space-y-4"
>
<el-form ref="leaveFormRef" v-loading="loading" :model="form" :rules="rules" label-width="100px" class="space-y-4">
<div class="grid grid-cols-1 gap-4">
<el-row>
<el-col :span="12">
<el-form-item label="版本号" prop="formNo">
<el-input disabled v-model="form.versions" placeholder="请输入文件名称" />
<el-input :disabled="true" v-model="form.versions" placeholder="请输入文件名称" />
</el-form-item>
<el-form-item label="表名" prop="formNo">
<el-input disabled v-model="form.sheet" placeholder="请输入文件名称" />
<el-form-item label="表名" prop="sheet">
<el-select v-model="form.sheet" placeholder="选择表名" @change="changeSheet">
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</el-col>
</el-row>
@ -50,7 +44,7 @@
<el-table-column prop="unitPrice" label="单价" align="center" />
<el-table-column prop="price" label="总价" align="center">
<template #default="scope">
{{ scope.row.price }}
{{ scope.row.price != 0 ? Number(scope.row.price).toFixed(2) : null }}
</template>
</el-table-column>
</el-table>
@ -76,12 +70,8 @@
</div>
<template #footer>
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
>取消</el-button
>
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
>确认</el-button
>
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors">取消</el-button>
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors">确认</el-button>
</div>
</template>
</el-dialog>
@ -99,7 +89,7 @@ import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
const { proxy } = getCurrentInstance() as any;
import { useUserStoreHook } from '@/store/modules/user';
const { design_change_reason_type } = toRefs<any>(proxy?.useDict('design_change_reason_type'));
import { listBillofquantitiesLimitList } from '@/api/contract/index';
import { listBillofquantitiesLimitList, getVersionDetails, sheetList } from '@/api/contract/index';
// 获取用户 store
const userStore = useUserStoreHook();
// 从 store 中获取项目列表和当前选中的项目
@ -143,7 +133,8 @@ const taskVariables = ref<Record<string, any>>({});
const initFormData = {
versions: '',
sheet: '',
status: ''
status: '',
id: ''
};
const data = reactive({
form: { ...initFormData },
@ -169,21 +160,47 @@ const getInfo = () => {
loading.value = true;
buttonLoading.value = false;
nextTick(async () => {
const res = await listBillofquantitiesLimitList({
projectId: routeParams.value?.id,
versions: routeParams.value.versions,
sheet: routeParams.value.sheet
});
console.log('res.data', res.data);
Object.assign(form.value, routeParams.value);
console.log('form', form.value);
tableData.value = res.data;
console.log('tableData', tableData.value);
const res = await getVersionDetails(routeParams.value.id);
console.log(res);
Object.assign(form.value, res.data);
loading.value = false;
buttonLoading.value = false;
getSheetName();
});
};
const sheets = ref([]);
//获取表名
const getSheetName = async () => {
try {
const params = {
projectId: currentProject.value?.id,
versions: form.value.versions
};
const res = await sheetList(params);
if (res.code == 200) {
sheets.value = res.data;
if (res.data.length > 0) {
form.value.sheet = res.data[0];
}
getListTable();
}
} catch (error) {}
};
//选择表名
const changeSheet = () => {
getListTable();
};
//获取列表
const getListTable = async () => {
const res = await listBillofquantitiesLimitList({
projectId: currentProject.value?.id,
versions: form.value.versions,
sheet: form.value.sheet
});
if (res.code == 200) {
tableData.value = res.data;
}
};
/** 提交按钮 */
const submitForm = (status1: string) => {
status.value = status1;
@ -198,7 +215,7 @@ const submitFlow = async () => {
const handleStartWorkFlow = async (data: any) => {
try {
submitFormData.value.flowCode = flowCode.value;
submitFormData.value.businessId = data.versions + '_xianjiayilan';
submitFormData.value.businessId = data.id;
//流程变量
taskVariables.value = {
// leave4/5 使用的流程变量
@ -216,7 +233,7 @@ const handleStartWorkFlow = async (data: any) => {
};
//审批记录
const handleApprovalRecord = () => {
approvalRecordRef.value.init(form.value.versions);
approvalRecordRef.value.init(form.value.id);
};
//提交回调
const submitCallback = async () => {
@ -255,7 +272,6 @@ onMounted(() => {
reset();
loading.value = false;
console.log(routeParams.value);
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
getInfo();
console.log('routeParams.value', routeParams.value);

View File

@ -1,66 +1,28 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<!-- <el-form-item label="项目ID" prop="projectId">
<el-input v-model="queryParams.projectId" placeholder="请输入项目ID" clearable @keyup.enter="handleQuery" />
</el-form-item> -->
<el-form-item label="合同编号" prop="contractCode">
<el-input v-model="queryParams.contractCode" placeholder="请输入合同编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="供应商" prop="contractSupplier">
<el-input v-model="queryParams.contractSupplier" placeholder="请输入供应商" clearable
@keyup.enter="handleQuery" />
<el-input v-model="queryParams.contractSupplier" placeholder="请输入供应商" clearable @keyup.enter="handleQuery" />
</el-form-item>
<!-- <el-form-item label="合同金额" prop="amount">
<el-input v-model="queryParams.amount" placeholder="请输入合同金额" clearable @keyup.enter="handleQuery" />
</el-form-item> -->
<!-- <el-form-item label="招标Id" prop="tenderId">
<el-input v-model="queryParams.tenderId" placeholder="请输入招标Id" clearable @keyup.enter="handleQuery" />
</el-form-item> -->
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<!-- <el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd"
v-hasPermi="['ctr:expensesContract:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
v-hasPermi="['ctr:expensesContract:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
v-hasPermi="['ctr:expensesContract:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport"
v-hasPermi="['ctr:expensesContract:export']">导出</el-button>
</el-col>-->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="expensesContractList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="主键ID" align="center" prop="id" v-if="true" /> -->
<el-table-column type="index" width="50" label="序号" />
<!-- <el-table-column label="项目ID" align="center" prop="projectId" /> -->
<el-table-column label="合同编号" align="center" prop="contractCode" />
<!-- <el-table-column label="合同类型" align="center" prop="contractType" /> -->
<el-table-column label="合同类型" align="center" prop="contractType">
<template #default="scope">
<dict-tag :options="expenses_contract_type" :value="scope.row.contractType" />
@ -73,37 +35,23 @@
</template>
</el-table-column>
<el-table-column label="供应商" align="center" prop="contractSupplier" />
<!-- <el-table-column label="分包内容" align="center" prop="contractedContent" /> -->
<el-table-column label="合同金额" align="center" prop="amount" />
<el-table-column label="预付款比例(%)" align="center" prop="advancePayRatio" />
<el-table-column label="尾款比例(%)" align="center" prop="balancePayRatio" />
<el-table-column label="质保金比例(%)" align="center" prop="assuranceDepositRatio" />
<el-table-column label="付款比例(%)" align="center" prop="payRatio" />
<!-- <el-table-column label="招标Id" align="center" prop="tenderId" /> -->
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<!-- <el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['ctr:expensesContract:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['ctr:expensesContract:remove']"></el-button>
</el-tooltip> -->
<div>
<el-button link type="success" icon="View" @click="handleShowDetail(scope.row)">查看分包内容</el-button>
</div>
<div>
<el-button link type="primary" icon="View" @click="handleShowFileList(scope.row)">查看附件列表</el-button>
</div>
<el-button link type="success" icon="View" @click="handleShowDetail(scope.row)">查看分包内容</el-button>
<el-button link type="primary" v-hasPermi="['ctr:expensesContract:query']" icon="View" @click="handleShowFileList(scope.row)"
>查看附件列表</el-button
>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改支出合同对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
@ -143,9 +91,7 @@
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="detailVisible = false">
关闭
</el-button>
<el-button type="primary" @click="detailVisible = false"> 关闭 </el-button>
</div>
</template>
</el-dialog>
@ -153,15 +99,20 @@
</template>
<script setup name="ExpensesContract" lang="ts">
import { listExpensesContract, getExpensesContract, delExpensesContract, addExpensesContract, updateExpensesContract, getFileList } from '@/api/ctr/expensesContract';
import {
listExpensesContract,
getExpensesContract,
delExpensesContract,
addExpensesContract,
updateExpensesContract,
getFileList
} from '@/api/ctr/expensesContract';
import { ExpensesContractVO, ExpensesContractQuery, ExpensesContractForm } from '@/api/ctr/expensesContract/types';
import FileList from '@/components/FileList/index.vue';
import useUserStore from '@/store/modules/user';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { expenses_contract_type, income_contract_type } = toRefs(
proxy?.useDict('income_contract_type', 'expenses_contract_type')
);
const { expenses_contract_type, income_contract_type } = toRefs(proxy?.useDict('income_contract_type', 'expenses_contract_type'));
const expensesContractList = ref<ExpensesContractVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
@ -193,8 +144,8 @@ const initFormData: ExpensesContractForm = {
contractedContent: undefined,
amount: undefined,
tenderId: undefined,
remark: undefined,
}
remark: undefined
};
const data = reactive<PageData<ExpensesContractForm, ExpensesContractQuery>>({
form: { ...initFormData },
queryParams: {
@ -207,16 +158,11 @@ const data = reactive<PageData<ExpensesContractForm, ExpensesContractQuery>>({
contractedContent: undefined,
amount: undefined,
tenderId: undefined,
params: {
}
params: {}
},
rules: {
id: [
{ required: true, message: "主键ID不能为空", trigger: "blur" }
],
projectId: [
{ required: true, message: "项目ID不能为空", trigger: "blur" }
],
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }]
}
});
@ -229,55 +175,55 @@ const getList = async () => {
expensesContractList.value = res.rows;
total.value = res.total;
loading.value = false;
}
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
}
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
expensesContractFormRef.value?.resetFields();
}
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
}
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: ExpensesContractVO[]) => {
ids.value = selection.map(item => item.id);
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = "添加支出合同";
}
dialog.title = '添加支出合同';
};
/** 修改按钮操作 */
const handleUpdate = async (row?: ExpensesContractVO) => {
reset();
const _id = row?.id || ids.value[0]
const _id = row?.id || ids.value[0];
const res = await getExpensesContract(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = "修改支出合同";
}
dialog.title = '修改支出合同';
};
/** 提交按钮 */
const submitForm = () => {
@ -285,46 +231,51 @@ const submitForm = () => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateExpensesContract(form.value).finally(() => buttonLoading.value = false);
await updateExpensesContract(form.value).finally(() => (buttonLoading.value = false));
} else {
await addExpensesContract(form.value).finally(() => buttonLoading.value = false);
await addExpensesContract(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess("操作成功");
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
}
};
/** 删除按钮操作 */
const handleDelete = async (row?: ExpensesContractVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除支出合同编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
await proxy?.$modal.confirm('是否确认删除支出合同编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delExpensesContract(_ids);
proxy?.$modal.msgSuccess("删除成功");
proxy?.$modal.msgSuccess('删除成功');
await getList();
}
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download('ctr/expensesContract/export', {
...queryParams.value
}, `expensesContract_${new Date().getTime()}.xlsx`)
}
proxy?.download(
'ctr/expensesContract/export',
{
...queryParams.value
},
`expensesContract_${new Date().getTime()}.xlsx`
);
};
// 查看附件列表操作
const handleShowFileList = async (row: ExpensesContractVO) => {
await getFileList({ contractId: row.id }).then(res => {
fileList.value = res.rows
fileListVisible.value = true;
}).catch(() => {
proxy?.$modal.error("获取文件列表失败");
});
}
await getFileList({ contractId: row.id })
.then((res) => {
fileList.value = res.rows;
fileListVisible.value = true;
})
.catch(() => {
proxy?.$modal.error('获取文件列表失败');
});
};
const handleShowDetail = (data) => {
detailContent.value = data.contractedContent
detailContent.value = data.contractedContent;
detailVisible.value = true;
}
};
onMounted(() => {
getList();
});

View File

@ -1,60 +1,26 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<!-- <el-form-item label="项目ID" prop="projectId">
<el-input v-model="queryParams.projectId" placeholder="请输入项目ID" clearable @keyup.enter="handleQuery" />
</el-form-item> -->
<el-form-item label="合同编号" prop="contractCode">
<el-input v-model="queryParams.contractCode" placeholder="请输入合同编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="业主单位" prop="contractOwner">
<el-input v-model="queryParams.contractOwner" placeholder="请输入业主单位" clearable
@keyup.enter="handleQuery" />
<el-input v-model="queryParams.contractOwner" placeholder="请输入业主单位" clearable @keyup.enter="handleQuery" />
</el-form-item>
<!-- <el-form-item label="合同金额" prop="amount">
<el-input v-model="queryParams.amount" placeholder="请输入合同金额" clearable @keyup.enter="handleQuery" />
</el-form-item> -->
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<!-- <el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd"
v-hasPermi="['ctr:incomeContract:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
v-hasPermi="['ctr:incomeContract:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
v-hasPermi="['ctr:incomeContract:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport"
v-hasPermi="['ctr:incomeContract:export']">导出</el-button>
</el-col>-->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="incomeContractList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="主键ID" align="center" prop="id" v-if="true" /> -->
<el-table-column type="index" width="50" label="序号" />
<!-- <el-table-column label="项目ID" align="center" prop="projectId" /> -->
<el-table-column label="合同编号" align="center" prop="contractCode" />
<el-table-column label="合同类型" align="center" prop="contractType">
<template #default="scope">
@ -68,7 +34,6 @@
</template>
</el-table-column>
<el-table-column label="业主单位" align="center" prop="contractOwner" />
<!-- <el-table-column label="承包内容" align="center" prop="contractedContent" /> -->
<el-table-column label="合同金额" align="center" prop="amount" />
<el-table-column label="预付款比例(%)" align="center" prop="advancePayRatio" />
<el-table-column label="尾款比例(%)" align="center" prop="balancePayRatio" />
@ -77,34 +42,24 @@
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template #default="scope">
<!-- <el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['ctr:incomeContract:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['ctr:incomeContract:remove']"></el-button>
</el-tooltip> -->
<!-- <el-tooltip content="查看承包内容" placement="top">
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)">详情</el-button>
</el-tooltip> -->
<div>
<el-button link type="primary" icon="edit" @click="handleEdit(scope.row)"
v-if="scope.row.isUpdate">修改合同</el-button>
</div>
<div>
<el-button link type="success" icon="View" @click="handleShowDetail(scope.row)">查看合同内容</el-button>
</div>
<div>
<el-button link type="primary" icon="View" @click="handleShowFileList(scope.row)">查看附件列表</el-button>
</div>
<el-button
link
type="primary"
v-hasPermi="['ctr:incomeContract:edit']"
icon="edit"
@click="handleEdit(scope.row)"
v-if="scope.row.isUpdate"
>修改合同</el-button
>
<el-button link type="success" icon="View" @click="handleShowDetail(scope.row)">查看合同内容</el-button>
<el-button link type="primary" v-hasPermi="['ctr:incomeContract:query']" icon="View" @click="handleShowFileList(scope.row)"
>查看附件列表</el-button
>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改收入合同对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
@ -141,9 +96,7 @@
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="detailVisible = false">
关闭
</el-button>
<el-button type="primary" @click="detailVisible = false"> 关闭 </el-button>
</div>
</template>
</el-dialog>
@ -151,20 +104,26 @@
</template>
<script setup name="IncomeContract" lang="ts">
import { listIncomeContract, getIncomeContract, delIncomeContract, addIncomeContract, updateIncomeContract, getFileList, getInfoByProjectId } from '@/api/ctr/incomeContract';
import {
listIncomeContract,
getIncomeContract,
delIncomeContract,
addIncomeContract,
updateIncomeContract,
getFileList,
getInfoByProjectId
} from '@/api/ctr/incomeContract';
import { IncomeContractVO, IncomeContractQuery, IncomeContractForm } from '@/api/ctr/incomeContract/types';
import FileList from '@/components/FileList/index.vue';
import useUserStore from '@/store/modules/user';
import { useRouter } from 'vue-router'
import { useRouter } from 'vue-router';
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const currentProject = computed(() => userStore.selectedProject);
const router = useRouter();
const { expenses_contract_type, income_contract_type } = toRefs(
proxy?.useDict('income_contract_type', 'expenses_contract_type')
);
const { expenses_contract_type, income_contract_type } = toRefs(proxy?.useDict('income_contract_type', 'expenses_contract_type'));
const incomeContractList = ref<IncomeContractVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
@ -191,8 +150,8 @@ const initFormData: IncomeContractForm = {
contractOwner: undefined,
contractedContent: undefined,
amount: undefined,
remark: undefined,
}
remark: undefined
};
const data = reactive<PageData<IncomeContractForm, IncomeContractQuery>>({
form: { ...initFormData },
queryParams: {
@ -204,16 +163,11 @@ const data = reactive<PageData<IncomeContractForm, IncomeContractQuery>>({
contractOwner: undefined,
contractedContent: undefined,
amount: undefined,
params: {
}
params: {}
},
rules: {
id: [
{ required: true, message: "主键ID不能为空", trigger: "blur" }
],
projectId: [
{ required: true, message: "项目ID不能为空", trigger: "blur" }
],
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }]
}
});
@ -226,55 +180,55 @@ const getList = async () => {
incomeContractList.value = res.rows;
total.value = res.total;
loading.value = false;
}
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
}
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
incomeContractFormRef.value?.resetFields();
}
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
}
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: IncomeContractVO[]) => {
ids.value = selection.map(item => item.id);
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = "添加收入合同";
}
dialog.title = '添加收入合同';
};
/** 修改按钮操作 */
const handleUpdate = async (row?: IncomeContractVO) => {
reset();
const _id = row?.id || ids.value[0]
const _id = row?.id || ids.value[0];
const res = await getIncomeContract(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = "修改收入合同";
}
dialog.title = '修改收入合同';
};
/** 提交按钮 */
const submitForm = () => {
@ -282,58 +236,63 @@ const submitForm = () => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateIncomeContract(form.value).finally(() => buttonLoading.value = false);
await updateIncomeContract(form.value).finally(() => (buttonLoading.value = false));
} else {
await addIncomeContract(form.value).finally(() => buttonLoading.value = false);
await addIncomeContract(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess("操作成功");
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
}
};
/** 删除按钮操作 */
const handleDelete = async (row?: IncomeContractVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除收入合同编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
await proxy?.$modal.confirm('是否确认删除收入合同编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delIncomeContract(_ids);
proxy?.$modal.msgSuccess("删除成功");
proxy?.$modal.msgSuccess('删除成功');
await getList();
}
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download('ctr/incomeContract/export', {
...queryParams.value
}, `incomeContract_${new Date().getTime()}.xlsx`)
}
proxy?.download(
'ctr/incomeContract/export',
{
...queryParams.value
},
`incomeContract_${new Date().getTime()}.xlsx`
);
};
// 查看附件列表操作
const handleShowFileList = async (row: IncomeContractVO) => {
console.log(row.id);
await getFileList({ contractId: row.id }).then(res => {
fileList.value = res.rows
fileListVisible.value = true;
}).catch(() => {
proxy?.$modal.error("获取文件列表失败");
});
}
await getFileList({ contractId: row.id })
.then((res) => {
fileList.value = res.rows;
fileListVisible.value = true;
})
.catch(() => {
proxy?.$modal.error('获取文件列表失败');
});
};
const handleEdit = (row: IncomeContractVO) => {
// console.log(router);
router.push({
path: "/ctr/update",
path: '/ctr/update',
query: {
id: row.id,
id: row.id
}
})
}
});
};
const handleShowDetail = (data) => {
detailContent.value = data.contractedContent
detailContent.value = data.contractedContent;
detailVisible.value = true;
}
};
onMounted(() => {
getList();
});

View File

@ -155,8 +155,8 @@
</template>
<script setup>
import FileUpload from '@/components/FileUpload';
import { listExpensesContract, getExpensesContract, delExpensesContract, addExpensesContract, updateExpensesContract, getTenderPlan } from '@/api/ctr/expensesContract';
import { listIncomeContract, getIncomeContract, delIncomeContract, addIncomeContract, updateIncomeContract, getInfoByProjectId } from '@/api/ctr/incomeContract';
import { addExpensesContract, getTenderPlan } from '@/api/ctr/expensesContract';
import { addIncomeContract, getInfoByProjectId } from '@/api/ctr/incomeContract';
import { useUserStore } from '@/store/modules/user';
const active = ref(0);

View File

@ -1,328 +1,226 @@
<template>
<div class="container">
<el-steps style="max-width: 100%" :active="active" finish-status="success" align-center>
<el-step title="选择合同类型" />
<el-step title="修改合同内容" />
<el-step title="修改收款方式" />
</el-steps>
<div class="content">
<template v-if="active == 1">
<h1>修改收入合同</h1>
<el-form ref="incomeContractFormRef" :model="form" :rules="incomeContractFormRules" label-width="80px">
<!-- <el-form-item label="项目名称">
<el-input :model-value="project.name" disabled />
</el-form-item> -->
<el-form-item label="合同编号" prop="contractCode">
<el-input v-model="form.contractCode" placeholder="请输入合同编号" />
</el-form-item>
<el-form-item label="合同类型" prop="contractType">
<el-select v-model="form.contractType" placeholder="请选择合同类型">
<el-option v-for="item in income_contract_type" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="业主单位" prop="contractOwner">
<el-input v-model="form.contractOwner" placeholder="请输入业主单位" disabled />
</el-form-item>
<el-form-item label="承包内容" v-if="contract_type !== 'income'">
<editor v-model="form.contractedContent" :min-height="192" />
</el-form-item>
<el-form-item label="合同内容" v-else>
<editor v-model="form.contractedContent" :min-height="192" />
</el-form-item>
<el-form-item label="合同金额" prop="amount">
<el-input v-model="form.amount" placeholder="请输入合同金额"
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
<el-form-item label="附件">
<FileUpload :multiple="true" :fileType="['pdf']" :onUploadSuccess="onUploadSuccess"
:ref="fileRef" :defaultFileList="tempFileList" />
</el-form-item>
</el-form>
<div>
<el-button type="primary" @click="next">下一步</el-button>
</div>
</template>
<template v-else-if="active == 2">
<h1>修改收入合同</h1>
<el-form :model="form" :rules="payMentRules" label-width="150" ref="payMentRef">
<el-form-item label="支付方式" placeholder="请选择支付方式" prop="payType">
<el-select v-model="form.payType">
<el-option :value="1" label="月结算">月结算</el-option>
<el-option :value="2" label="形象节点">形象节点</el-option>
</el-select>
</el-form-item>
<el-form-item label="预付款比例(%" prop="advancePayRatio">
<el-input-number v-model="form.advancePayRatio" :max="100" :min="0" />
</el-form-item>
<el-form-item label="尾款比例(%" prop="balancePayRatio">
<el-input-number v-model="form.balancePayRatio" :max="100" :min="0" />
</el-form-item>
<el-form-item label="质保金比例(%" prop="assuranceDepositRatio">
<el-input-number v-model="form.assuranceDepositRatio" :max="100" :min="0" />
</el-form-item>
<el-form-item label="付款比例(%" prop="payRatio">
<el-input-number v-model="payRatioComputed" disabled />
</el-form-item>
<el-form-item>
<div>
<el-button @click="back(false)">上一步</el-button>
<el-button type="success" @click="submitForm">提交</el-button>
</div>
</el-form-item>
</el-form>
</template>
<div class="container">
<el-steps style="max-width: 100%" :active="active" finish-status="success" align-center>
<el-step title="选择合同类型" />
<el-step title="修改合同内容" />
<el-step title="修改收款方式" />
</el-steps>
<div class="content">
<template v-if="active == 1">
<h1>修改收入合同</h1>
<el-form ref="incomeContractFormRef" :model="form" :rules="incomeContractFormRules" label-width="80px">
<el-form-item label="合同编号" prop="contractCode">
<el-input v-model="form.contractCode" placeholder="请输入合同编号" />
</el-form-item>
<el-form-item label="合同类型" prop="contractType">
<el-select v-model="form.contractType" placeholder="请选择合同类型">
<el-option v-for="item in income_contract_type" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="业主单位" prop="contractOwner">
<el-input v-model="form.contractOwner" placeholder="请输入业主单位" disabled />
</el-form-item>
<el-form-item label="承包内容" v-if="contract_type !== 'income'">
<editor v-model="form.contractedContent" :min-height="192" />
</el-form-item>
<el-form-item label="合同内容" v-else>
<editor v-model="form.contractedContent" :min-height="192" />
</el-form-item>
<el-form-item label="合同金额" prop="amount">
<el-input
v-model="form.amount"
placeholder="请输入合同金额"
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
<el-form-item label="附件">
<FileUpload :multiple="true" :fileType="['pdf']" :onUploadSuccess="onUploadSuccess" :ref="fileRef" :defaultFileList="tempFileList" />
</el-form-item>
</el-form>
<div>
<el-button type="primary" @click="next">下一步</el-button>
</div>
</template>
<template v-else-if="active == 2">
<h1>修改收入合同</h1>
<el-form :model="form" :rules="payMentRules" label-width="150" ref="payMentRef">
<el-form-item label="支付方式" placeholder="请选择支付方式" prop="payType">
<el-select v-model="form.payType">
<el-option :value="1" label="月结算">月结算</el-option>
<el-option :value="2" label="形象节点">形象节点</el-option>
</el-select>
</el-form-item>
<el-form-item label="预付款比例(%" prop="advancePayRatio">
<el-input-number v-model="form.advancePayRatio" :max="100" :min="0" />
</el-form-item>
<el-form-item label="尾款比例(%" prop="balancePayRatio">
<el-input-number v-model="form.balancePayRatio" :max="100" :min="0" />
</el-form-item>
<el-form-item label="质保金比例(%" prop="assuranceDepositRatio">
<el-input-number v-model="form.assuranceDepositRatio" :max="100" :min="0" />
</el-form-item>
<el-form-item label="付款比例(%" prop="payRatio">
<el-input-number v-model="payRatioComputed" disabled />
</el-form-item>
<el-form-item>
<div>
<el-button @click="back(false)">上一步</el-button>
<el-button type="success" @click="submitForm">提交</el-button>
</div>
</el-form-item>
</el-form>
</template>
</div>
</div>
</template>
<script setup>
import FileUpload from '@/components/FileUpload';
import { listExpensesContract, getExpensesContract, delExpensesContract, addExpensesContract, updateExpensesContract, getTenderPlan } from '@/api/ctr/expensesContract';
import { listIncomeContract, getIncomeContract, delIncomeContract, addIncomeContract, updateIncomeContract } from '@/api/ctr/incomeContract';
import { getTenderPlan } from '@/api/ctr/expensesContract';
import { updateIncomeContract } from '@/api/ctr/incomeContract';
import { useUserStore } from '@/store/modules/user';
const active = ref(1);
const contract_type = ref("income")
const form = ref({ payType: 1 })
const fileList = ref([])
const tempFileList = ref([])
const contract_type = ref('income');
const form = ref({ payType: 1 });
const fileList = ref([]);
const tempFileList = ref([]);
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const planList = ref([]);
const dialogVisible = ref(false);
const route = useRoute();
const router = useRouter();
const { expenses_contract_type, income_contract_type } = toRefs(
proxy?.useDict('income_contract_type', 'expenses_contract_type')
);
const { income_contract_type } = toRefs(proxy?.useDict('income_contract_type', 'expenses_contract_type'));
const fileRef = ref(null);
const incomeContractFormRef = ref(null);
const expensesContractFormRef = ref(null);
const payMentRef = ref(null);
const incomeContractFormRules = {
contractCode: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
contractOwner: [{ required: true, message: '请输入业主单位', trigger: 'blur' }],
amount: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
remark: [{ required: false, message: '请输入备注', trigger: 'blur' }],
contractCode: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
contractOwner: [{ required: true, message: '请输入业主单位', trigger: 'blur' }],
amount: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
remark: [{ required: false, message: '请输入备注', trigger: 'blur' }]
};
const expensesContractFormRules = {
contractCode: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
contractCode: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
contractSupplier: [{ required: true, message: '请输入供应商', trigger: 'blur' }],
amount: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
tenderId: [{ required: true, message: '请选择招标计划', trigger: 'blur' }],
contractSupplier: [{ required: true, message: '请输入供应商', trigger: 'blur' }],
amount: [{ required: true, message: '请输入合同金额', trigger: 'blur' }],
tenderId: [{ required: true, message: '请选择招标计划', trigger: 'blur' }],
remark: [{ required: false, message: '请输入备注', trigger: 'blur' }],
remark: [{ required: false, message: '请输入备注', trigger: 'blur' }]
};
const payMentRules = {
payType: [{ required: true, message: '请选择支付方式', trigger: 'change' }],
advancePayRatio: [{ required: true, message: '请输入预付款比例', trigger: 'blur' }],
balancePayRatio: [{ required: true, message: '请输入尾款比例', trigger: 'blur' }],
assuranceDepositRatio: [{ required: true, message: '请输入质保金比例', trigger: 'blur' }],
payType: [{ required: true, message: '请选择支付方式', trigger: 'change' }],
advancePayRatio: [{ required: true, message: '请输入预付款比例', trigger: 'blur' }],
balancePayRatio: [{ required: true, message: '请输入尾款比例', trigger: 'blur' }],
assuranceDepositRatio: [{ required: true, message: '请输入质保金比例', trigger: 'blur' }]
};
const project = computed(() => {
return JSON.parse(localStorage.getItem("selectedProject"))
return JSON.parse(localStorage.getItem('selectedProject'));
});
const payRatioComputed = computed({
get: () => {
const { advancePayRatio = 0, balancePayRatio = 0, assuranceDepositRatio = 0 } = form.value;
const total = 100 - (advancePayRatio + balancePayRatio + assuranceDepositRatio);
// form.value.payRatio = total;
return total;
},
// 只读
set: () => { }
get: () => {
const { advancePayRatio = 0, balancePayRatio = 0, assuranceDepositRatio = 0 } = form.value;
const total = 100 - (advancePayRatio + balancePayRatio + assuranceDepositRatio);
// form.value.payRatio = total;
return total;
},
// 只读
set: () => {}
});
const onUploadSuccess = (data) => {
fileList.value = data
}
fileList.value = data;
};
const next = async () => {
if (contract_type.value === 'income') {
await incomeContractFormRef.value.validate((valid) => {
if (valid) {
active.value++;
} else {
ElMessage.error('请填写完整的收入合同信息');
}
});
} else if (contract_type.value === 'expenses') {
await expensesContractFormRef.value.validate((valid) => {
if (valid) {
active.value++;
} else {
ElMessage.error('请填写完整的支出合同信息');
}
});
}
console.log(active.value);
if (contract_type.value === 'income') {
await incomeContractFormRef.value.validate((valid) => {
if (valid) {
active.value++;
} else {
ElMessage.error('请填写完整的收入合同信息');
}
});
} else if (contract_type.value === 'expenses') {
await expensesContractFormRef.value.validate((valid) => {
if (valid) {
active.value++;
} else {
ElMessage.error('请填写完整的支出合同信息');
}
});
}
console.log(active.value);
form.value.step = active.value;
form.value.step = active.value;
};
const submitForm = async () => {
await payMentRef.value.validate(async (valid) => {
if (valid) {
await payMentRef.value.validate(async (valid) => {
if (valid) {
if (payRatioComputed.value < 0) {
ElMessage.error('四项付款比例之和必须等于100%');
return;
}
form.value.payRatio = payRatioComputed.value;
if (payRatioComputed.value < 0) {
ElMessage.error('四项付款比例之和必须等于100%');
return;
}
form.value.payRatio = payRatioComputed.value;
// 提交付款信息逻辑
console.log('提交付款信息', form.value, fileList.value);
// 这里可以调用API提交数据
form.value.projectId = project.value.id;
form.value.fileList = fileList.value.map((data) => {
return {
...data,
fileName: data.name,
fileUrl: data.url,
}
})
if (contract_type.value === 'income') {
await updateIncomeContract({ ...form.value });
}
ElMessage.success('合同修改成功');
} else {
ElMessage.error('请填写完整的付款信息');
}
});
}
// 提交付款信息逻辑
console.log('提交付款信息', form.value, fileList.value);
// 这里可以调用API提交数据
form.value.projectId = project.value.id;
form.value.fileList = fileList.value.map((data) => {
return {
...data,
fileName: data.name,
fileUrl: data.url
};
});
if (contract_type.value === 'income') {
await updateIncomeContract({ ...form.value });
}
ElMessage.success('合同修改成功');
} else {
ElMessage.error('请填写完整的付款信息');
}
});
};
const handleChoose = async () => {
if (!form.value.contractType) {
ElMessage.error('请先选择合同类型');
return;
}
const formData = {
projectId: userStore.selectedProject.id,
dictName: form.value.contractType,
status: 1,
}
const { data } = await getTenderPlan(formData)
if (data.length === 0) {
ElMessage.warning('当前没有招标计划,请先创建招标计划');
return;
}
planList.value = data
dialogVisible.value = true;
if (!form.value.contractType) {
ElMessage.error('请先选择合同类型');
return;
}
const formData = {
projectId: userStore.selectedProject.id,
dictName: form.value.contractType,
status: 1
};
const { data } = await getTenderPlan(formData);
if (data.length === 0) {
ElMessage.warning('当前没有招标计划,请先创建招标计划');
return;
}
planList.value = data;
dialogVisible.value = true;
};
}
onMounted(async () => {
// const id = route.query.id;
// if (id) {
// const { data } = await getIncomeContract(id);
// form.value.id = data.id;
// form.value.contractOwner = data.contractOwner
// } else {
// router.push('/ctr/incomeContract');
// }
proxy?.download(
'/progress/progressCategory/export',
{
"ids": [
"1951552037761114114",
"1951552037811445761",
"1951552037811445762",
"1951552037811445763",
"1951552037811445764",
"1951552037811445765",
"1951552037811445766",
"1951552037811445767",
"1951552037865971713",
"1951552037865971714",
"1951552037865971715",
"1951552037865971716",
"1951552037865971717",
"1951552037865971718",
"1951552037865971719",
"1951552037865971720",
"1951552037865971721",
"1951552037865971722",
"1951552037865971723",
"1951552037865971724",
"1951552037865971725",
"1951552037924691969",
"1951552037924691970",
"1951552037924691971",
"1951552037924691972",
"1951552037924691973",
"1951552037924691974",
"1951552037924691975",
"1951552037924691976",
"1951552037924691977",
"1951552037962440706",
"1951552037962440707",
"1951552037962440708",
"1951552037962440709",
"1951552037962440710",
"1951552037962440711",
"1951552037962440712",
"1951552038004383745",
"1951552038004383746",
"1951552038004383747",
"1951552038004383748",
"1951552038004383749",
"1951552038004383750",
"1951552038004383751",
"1951552038004383752",
"1951552038004383753",
"1951552038004383754",
"1951552038058909698",
"1951552038058909699",
"1951552038058909700",
"1951552038058909701",
"1951552038058909702",
"1951552038058909703",
"1951552038058909704",
"1951552038096658434",
"1951552038096658435",
"1951552038096658436",
"1951552038096658437",
"1951552038096658438",
"1951552038096658439",
"1951552038096658440",
"1951552038096658441",
"1951552038096658442",
"1951552038096658443",
"1951552038096658444",
"1951552038146990081",
"1951552038146990082",
"1951552038146990083",
"1951552038146990084",
"1951552038146990085",
"1951552038188933122",
"1951552038188933123",
"1951552038188933124"
]
},
`1.xlsx`
);
})
onMounted(async () => {});
</script>
<style scoped lang="scss">
.container {
padding: 20px;
padding: 20px;
.content {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 30px;
flex-direction: column;
}
.content {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 30px;
flex-direction: column;
}
}
</style>

View File

@ -19,7 +19,7 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
<el-button type="primary" plain icon="Plus" v-hasPermi="['design:extract:add']" @click="handleAdd">新增</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -38,7 +38,14 @@
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['design:extract:query']">审核</el-button>
<el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['design:extract:export']">导出</el-button
<el-button
link
type="primary"
v-if="scope.row.status != 'finish'"
icon="Download"
@click="handleDownload(scope.row)"
v-hasPermi="['design:extract:export']"
>导出</el-button
><el-button
link
type="warning"
@ -65,15 +72,17 @@
<el-table :loading="loadingFlie" :data="fileList" style="width: 100%" border>
<el-table-column prop="fileName" label="文件名称" align="center">
<template #default="scope">
<el-link
<!-- <el-link
:key="scope.row.fileId"
:href="scope.row.fileUrl"
target="_blank"
:type="scope.row.status == '1' ? 'primary' : 'info'"
:underline="false"
disabled
>
{{ scope.row.fileName }}
</el-link>
</el-link> -->
<span>{{ scope.row.fileName }}</span>
</template>
</el-table-column>
<el-table-column label="版本号" align="center" width="120" prop="version"> </el-table-column>
@ -187,7 +196,7 @@ const handleDownload = (row) => {
{
id: row.id
},
`互提资料.zip`
`互提资料.docx`
);
};
const handleViewFile = (row) => {

View File

@ -445,7 +445,9 @@ const getMajor = async () => {
let res = await extractUserMajor({ userId: userId.value, projectId: currentProject.value?.id });
if (res.code == 200) {
des_user_major.value = res.data;
console.log(des_user_major.value);
if (res.data.length > 0) {
form.user_major = res.data[0].userMajor;
}
}
};
/** 回显表单数据(编辑/查看/审批场景) */

View File

@ -0,0 +1,804 @@
<template>
<div class="p-6 bg-gray-50">
<div class="appointment mx-auto bg-white rounded-xl shadow-sm overflow-hidden transition-all duration-300 hover:shadow-md">
<!-- 表单标题区域 -->
<div class="bg-gradient-to-r from-blue-500 to-blue-600 text-white p-6">
<h2 class="text-2xl font-bold flex items-center"><i class="el-icon-user-circle mr-3"></i>人员配置</h2>
<p class="text-blue-100 mt-2 opacity-90">请配置项目相关负责人员信息</p>
<el-button @click="disabledForm = false" class="px-8 py-2.5 transition-all duration-300 font-medium" v-if="disabledForm">
点击编辑
</el-button>
</div>
<!-- 表单内容区域 -->
<el-form ref="leaveFormRef" :model="form" :disabled="disabledForm" :rules="rules" label-width="120px" class="p-6 space-y-6">
<!-- 设计负责人 -->
<div class="fonts">
<el-row>
<el-col :span="8"
><el-form-item label="设计负责人" prop="designLeader" class="mb-4">
<el-select
v-model="form.designLeader"
placeholder="请选择设计负责人"
class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400"
>
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 专业人员配置专业 + 设计人员 + 校审人员 横向排列 -->
<div class="border border-gray-200 rounded-lg p-5 transition-all duration-300 hover:shadow-md bg-gray-50">
<div class="flex justify-between items-center mb-5">
<h3 class="text-lg font-semibold text-gray-700 flex items-center"><i class="el-icon-users mr-2 text-blue-500"></i>专业人员配置</h3>
<div class="flex gap-3">
<!-- 新增专业按钮 -->
<el-button type="primary" size="small" :disabled="disabledForm" @click="addMajor">
<i class="el-icon-plus mr-1"></i>新增专业
</el-button>
</div>
</div>
<!-- 表头 -->
<el-row :gutter="20" class="mb-3 font-medium text-gray-700">
<el-col :span="6" :xs="24" :sm="8">专业</el-col>
<el-col :span="9" :xs="24" :sm="8">设计人员可多选</el-col>
<el-col :span="9" :xs="24" :sm="8">校审人员可多选</el-col>
</el-row>
<!-- 分割线 -->
<el-divider class="my-4" />
<!-- 专业配置行专业+ 设计人员+ 校审人员 横向排列 -->
<div
v-for="(majorConfig, configIndex) in combinedConfigs"
:key="configIndex"
style="background: aliceblue; border-radius: 10px"
class="mb-5 animate-fadeIn"
>
<el-row :gutter="20" class="items-top">
<!-- 左侧专业选择 -->
<el-col :span="6" :xs="24" :sm="8" class="mb-4 sm:mb-0" style="margin-top: 8px">
<el-form-item
:prop="`designers.${configIndex}.userMajor`"
:rules="{ required: true, message: '请选择专业', trigger: 'change' }"
class="mb-0"
label-width="80px"
label="专业"
>
<!-- 专业选择下拉框 -->
<el-select
v-model="form.designers[configIndex].userMajor"
placeholder="请选择专业"
class="w-full transition-all duration-300 border-gray-300"
@change="(val) => handleMajorChange(val, configIndex)"
>
<!-- 临时添加调试显示 -->
<template v-if="des_user_major && des_user_major.length > 0">
<el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" />
</template>
<template v-else>
<el-option label="无专业数据" value="" disabled />
</template>
</el-select>
</el-form-item>
</el-col>
<!-- 中间设计人员 -->
<el-col :span="9" :xs="24" :sm="8" class="mb-4 sm:mb-0">
<div class="pl-0 sm:pl-4 border-l-0 sm:border-l-2 border-blue-200 py-0 sm:py-2">
<!-- 设计人员列表 -->
<div class="space-y-3">
<div v-for="(person, personIndex) in majorConfig.designPersons" :key="personIndex" class="flex items-center">
<el-form-item
:prop="`designers.${configIndex}.persons.${personIndex}.userId`"
:rules="{ required: true, message: '请选择人员', trigger: 'change' }"
class="flex-1 mr-3 mb-0"
label="设计人员"
label-width="80px"
>
<el-select
v-model="person.userId"
placeholder="请选择设计人员"
class="w-full transition-all duration-300 border-gray-300"
@change="() => checkDuplicate(person, 'designers', configIndex, personIndex)"
>
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
<div>
<el-button
type="danger"
size="small"
@click="removePerson('designers', configIndex, personIndex)"
class="transition-all duration-300 hover:bg-red-600"
:disabled="majorConfig.designPersons.length <= 1 || disabledForm"
>
<el-icon :size="16">
<Delete />
</el-icon>
</el-button>
<el-button
type="success"
size="small"
@click="addPerson('designers', configIndex)"
class="transition-all duration-300 transform hover:scale-105"
:disabled="!majorConfig.userMajor || disabledForm"
>
<el-icon :size="16">
<Plus />
</el-icon>
</el-button>
</div>
</div>
</div>
<!-- 空状态提示 -->
<div
v-if="majorConfig.designPersons.length == 0"
class="text-gray-500 text-sm py-2 bg-gray-100 rounded-lg border border-dashed border-gray-200 mt-1"
>
暂无设计人员请点击"添加设计人员"
</div>
</div>
</el-col>
<!-- 右侧校审人员 -->
<el-col :span="9" :xs="24" :sm="8">
<div class="pl-0 sm:pl-4 border-l-0 sm:border-l-2 border-green-200 py-0 sm:py-2">
<!-- 校审人员列表 -->
<div class="space-y-3">
<div v-for="(person, personIndex) in majorConfig.reviewPersons" :key="personIndex" class="flex items-center">
<el-form-item
:prop="`reviewers.${configIndex}.persons.${personIndex}.userId`"
:rules="{ required: true, message: '请选择人员', trigger: 'change' }"
class="flex-1 mr-3 mb-0"
label="校审人员"
label-width="80px"
>
<el-select
v-model="person.userId"
placeholder="请选择校审人员"
class="w-full transition-all duration-300 border-gray-300"
@change="() => checkDuplicate(person, 'reviewers', configIndex, personIndex)"
>
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
<div>
<el-button
type="danger"
size="small"
@click="removePerson('reviewers', configIndex, personIndex)"
class="transition-all duration-300 hover:bg-red-600"
:disabled="majorConfig.reviewPersons.length <= 1 || disabledForm"
>
<el-icon :size="16">
<Delete />
</el-icon>
</el-button>
<el-button
type="success"
size="small"
@click="addPerson('reviewers', configIndex)"
class="transition-all duration-300 transform hover:scale-105"
:disabled="!majorConfig.userMajor || disabledForm"
>
<el-icon :size="16">
<Plus />
</el-icon>
</el-button>
</div>
</div>
</div>
<!-- 空状态提示 -->
<div
v-if="majorConfig.reviewPersons.length == 0"
class="text-gray-500 text-sm py-2 bg-gray-100 rounded-lg border border-dashed border-gray-200 mt-1"
>
暂无校审人员请点击"添加校审人员"
</div>
</div>
</el-col>
</el-row>
<!-- 删除专业配置行 -->
<el-row class="mt-2">
<el-col :span="24" class="text-right pr-4">
<el-button
type="text"
class="text-red-500 hover:text-red-700 transition-colors"
@click="removeMajor(configIndex)"
:disabled="combinedConfigs.length <= 1 || disabledForm"
>
<i class="el-icon-delete mr-1"></i>删除专业
</el-button>
</el-col>
</el-row>
</div>
</div>
<!-- 提交按钮区域 -->
<div class="flex justify-center space-x-6 mt-8 pt-6 border-t border-gray-100">
<el-button
type="primary"
size="large"
v-hasPermi="['design:user:batch']"
@click="submitForm"
class="px-8 py-2.5 transition-all duration-300 transform hover:scale-105 bg-blue-500 hover:bg-blue-600 text-white font-medium"
:disabled="disabledForm"
>
<i class="el-icon-check mr-2"></i>确认提交
</el-button>
<el-button
size="large"
@click="resetForm"
class="px-8 py-2.5 transition-all duration-300 border-gray-300 hover:bg-gray-100 font-medium"
:disabled="disabledForm"
>
<i class="el-icon-refresh mr-2"></i>重置
</el-button>
</div>
</el-form>
</div>
</div>
</template>
<script setup name="PersonnelForm" lang="ts">
import { ref, reactive, computed, onMounted, toRefs, watch, WatchStopHandle } from 'vue';
import { getCurrentInstance } from 'vue';
import type { ComponentInternalInstance } from 'vue';
import { useUserStoreHook } from '@/store/modules/user';
import { ElMessage, ElLoading } from 'element-plus';
import { Delete, Plus } from '@element-plus/icons-vue'; // 修复添加Plus图标导入
import { designUserAdd, designUserList, systemUserList } from '@/api/design/appointment';
// 获取当前实例
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 获取用户 store
const userStore = useUserStoreHook();
// 从 store 中获取当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
// 专业字典数据 - 增加默认空数组避免undefined
const { des_user_major = ref([]) } = toRefs<any>(proxy?.useDict('des_user_major') || {});
// 调试:打印专业数据
onMounted(() => {
console.log('专业数据:', des_user_major.value);
});
// 表单数据:保持原有数据结构不变
interface MajorGroup {
userMajor: string | null; // 专业
persons: Array<{ userId: number | null }>; // 该专业下的多个人员
}
const form = reactive({
projectId: currentProject.value?.id,
designLeader: null, // 设计负责人
designers: [] as MajorGroup[], // 设计人员:按专业分组,每组含多个人员
reviewers: [] as MajorGroup[] // 校审人员:按专业分组,每组含多个人员
});
// 组合配置用于视图展示(专业+设计人员+校审人员)
const combinedConfigs = computed(() => {
// 确保designers和reviewers数组长度一致
const maxLength = Math.max(form.designers.length, form.reviewers.length);
while (form.designers.length < maxLength) {
form.designers.push(createEmptyMajorGroup());
}
while (form.reviewers.length < maxLength) {
form.reviewers.push(createEmptyMajorGroup());
}
// 组合数据用于视图展示
return form.designers.map((designerGroup, index) => ({
userMajor: designerGroup.userMajor,
designPersons: designerGroup.persons,
reviewPersons: form.reviewers[index].persons
}));
});
// 表单验证规则
const rules = reactive({
designLeader: [{ required: true, message: '请选择设计负责人', trigger: 'change' }]
});
// 用户列表
const userList = ref([]);
// 表单引用
const leaveFormRef = ref();
const disabledForm = ref(false); //控制提交按钮状态
/** 查询当前部门的所有用户 */
const getDeptAllUser = async (deptId: any) => {
try {
const res = await systemUserList({ deptId });
userList.value = res.rows;
} catch (error) {
ElMessage.error('获取用户列表失败');
}
};
/** 查询当前表单数据并回显 */
const designUser = async () => {
if (!currentProject.value?.id) return;
const loading = ElLoading.service({
lock: true,
text: '加载配置数据中...',
background: 'rgba(255, 255, 255, 0.7)'
});
try {
const res = await designUserList({ projectId: currentProject.value?.id });
// 清空现有数据
form.designLeader = null;
form.designers = [];
form.reviewers = [];
if (res.code == 200 && res.rows && res.rows.length > 0) {
disabledForm.value = true;
// 1. 分类整理数据(按用户类型)
const designLeader = res.rows.find((item) => item.userType == 1);
const designerItems = res.rows.filter((item) => item.userType == 2);
const reviewerItems = res.rows.filter((item) => item.userType == 3);
// 2. 回显设计负责人
if (designLeader) form.designLeader = designLeader.userId;
// 3. 回显设计人员(按专业分组)
form.designers = groupPersonByMajor(designerItems);
// 4. 回显校审人员(按专业分组)
form.reviewers = groupPersonByMajor(reviewerItems);
}
// 补全默认空项至少1个专业分组每组至少1个人员
if (form.designers.length == 0) form.designers.push(createEmptyMajorGroup());
if (form.reviewers.length == 0) form.reviewers.push(createEmptyMajorGroup());
} catch (error) {
ElMessage.error('获取配置数据失败');
// 异常时初始化默认空项
form.designers = [createEmptyMajorGroup()];
form.reviewers = [createEmptyMajorGroup()];
} finally {
loading.close();
}
};
/** 辅助函数创建空的专业分组含1个空人员 */
const createEmptyMajorGroup = (): MajorGroup => ({
userMajor: null,
persons: [{ userId: null }]
});
/** 辅助函数:按专业分组整理人员数据(用于回显) */
const groupPersonByMajor = (items: any[]): MajorGroup[] => {
const groupMap: Record<string, MajorGroup> = {};
items.forEach((item) => {
const major = item.userMajor || '未分类';
// 不存在该专业分组则创建
if (!groupMap[major]) {
groupMap[major] = { userMajor: item.userMajor, persons: [] };
}
// 添加当前人员到专业分组
groupMap[major].persons.push({ userId: item.userId });
});
// 处理空分组确保每组至少1个人员
Object.values(groupMap).forEach((group) => {
if (group.persons.length == 0) group.persons.push({ userId: null });
});
return Object.values(groupMap);
};
/** 新增专业配置行 */
const addMajor = () => {
form.designers.push(createEmptyMajorGroup());
form.reviewers.push(createEmptyMajorGroup());
// 滚动到新增的专业配置行
setTimeout(() => {
const groups = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .animate-fadeIn`);
if (groups.length > 0) {
groups[groups.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}, 100);
};
/** 删除专业配置行 */
const removeMajor = (configIndex: number) => {
if (form.designers.length <= 1) {
ElMessage.warning('至少保留一个专业配置');
return;
}
form.designers.splice(configIndex, 1);
form.reviewers.splice(configIndex, 1);
};
/** 给指定专业配置行添加人员 */
const addPerson = (type: 'designers' | 'reviewers', configIndex: number) => {
form[type][configIndex].persons.push({ userId: null });
// 滚动到新增的人员选择框
setTimeout(() => {
const personSelects = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .el-select`);
if (personSelects.length > 0) {
personSelects[personSelects.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}, 100);
};
/** 从指定专业配置行删除人员 */
const removePerson = (type: 'designers' | 'reviewers', configIndex: number, personIndex: number) => {
const targetGroup = form[type][configIndex];
if (targetGroup.persons.length <= 1) {
ElMessage.warning(`该专业至少保留一个${type == 'designers' ? '设计' : '校审'}人员`);
return;
}
targetGroup.persons.splice(personIndex, 1);
};
/** 专业变更时:清空当前专业下的人员(避免专业与人员不匹配) */
const handleMajorChange = (newMajor: string, configIndex: number) => {
// 直接修改原始数据源,确保响应式生效
form.designers[configIndex].userMajor = newMajor;
form.reviewers[configIndex].userMajor = newMajor;
form.designers[configIndex].persons = [{ userId: null }];
form.reviewers[configIndex].persons = [{ userId: null }];
// ElMessage.info(`已重置「${getMajorLabel(newMajor)}」专业下的人员,请重新选择`);
};
// ========== 核心:重复校验逻辑 ==========
/**
* 校验同一角色内(设计/校审)的「专业+人员」组合唯一性
*/
const checkDuplicate = (current: { userId: number | null }, role: 'designers' | 'reviewers', configIndex: number, personIndex: number) => {
console.log(`校验触发 - 角色: ${role}, 专业索引: ${configIndex}, 人员索引: ${personIndex}, 人员ID: ${current.userId}`);
console.log(form);
const currentGroup = form[role][configIndex];
// 未选专业/人员时不校验
if (!currentGroup.userMajor || !current.userId) return;
// 生成当前「专业+人员」唯一标识
const currentKey = `${currentGroup.userMajor}-${current.userId}`;
let duplicateItem = null;
// 1. 检查当前专业配置行内是否有重复人员
duplicateItem = currentGroup.persons.find((item, idx) => {
return idx !== personIndex && item.userId == current.userId;
});
if (duplicateItem) {
ElMessage.warning(`当前专业下「${getUserName(current.userId)}」已存在,请重新选择`);
current.userId = null;
return;
}
// 2. 检查同一角色内其他专业配置行是否有重复(专业+人员唯一)
form[role].forEach((group, gIdx) => {
if (gIdx == configIndex) return; // 跳过当前配置行
group.persons.forEach((item) => {
if (`${group.userMajor}-${item.userId}` == currentKey) {
duplicateItem = item;
}
});
});
if (duplicateItem) {
ElMessage.warning(`${getMajorLabel(currentGroup.userMajor)}+${getUserName(current.userId)}」组合已存在,请重新选择`);
current.userId = null;
}
};
/** 辅助函数:通过专业值获取专业名称 */
const getMajorLabel = (majorValue: string | null) => {
if (!majorValue || !des_user_major.value) return '';
const major = des_user_major.value.find((item: any) => item.value == majorValue);
return major ? major.label : majorValue;
};
/** 辅助函数通过用户ID获取用户名 */
const getUserName = (userId: number | null) => {
if (!userId || !userList.value.length) return '';
const user = userList.value.find((item: any) => item.userId == userId);
return user ? user.nickName : userId;
};
/** 提交表单(保持原有数据结构) */
const submitForm = async () => {
if (!leaveFormRef.value) return;
try {
// 1. 基础表单验证
await leaveFormRef.value.validate();
// 2. 提交前二次校验:「专业+人员」组合唯一性
let hasDuplicate = false;
const allKeys: string[] = [];
// 收集所有「专业+人员」组合(设计+校审分开校验)
const collectKeys = (roleGroups: MajorGroup[], roleName: string) => {
roleGroups.forEach((group) => {
if (!group.userMajor) return;
group.persons.forEach((person) => {
if (!person.userId) return;
const key = `${group.userMajor}-${person.userId}`;
if (allKeys.includes(key)) {
hasDuplicate = true;
ElMessage.error(`${roleName}中存在重复的「专业+人员」组合,请检查`);
}
allKeys.push(key);
});
});
};
// 校验设计人员
collectKeys(form.designers, '设计人员');
if (hasDuplicate) return;
// 清空临时数组,校验校审人员(不校验设计与校审之间)
allKeys.length = 0;
collectKeys(form.reviewers, '校审人员');
if (hasDuplicate) return;
// 3. 构建提交数据(适配后端原有数据格式)
const submitData = {
projectId: form.projectId,
personnel: [
// 设计负责人
{
userId: form.designLeader,
userType: 'designLeader',
userMajor: null
},
// 设计人员:展开专业分组,每个人员单独作为一条数据
...form.designers.flatMap((group) =>
group.persons.map((person) => ({
userId: person.userId,
userType: 'designer',
userMajor: group.userMajor
}))
),
// 校审人员:展开专业分组,每个人员单独作为一条数据
...form.reviewers.flatMap((group) =>
group.persons.map((person) => ({
userId: person.userId,
userType: 'reviewer',
userMajor: group.userMajor
}))
)
]
};
// 4. 数据处理(保持原有逻辑不变)
const arr = [];
userList.value.forEach((item) => {
submitData.personnel.forEach((item1) => {
if (item1.userId == item.userId) {
let userType = 1;
if (item1.userType == 'designer') userType = 2;
else if (item1.userType == 'reviewer') userType = 3;
arr.push({
userName: item.nickName,
projectId: submitData.projectId,
userId: item1.userId,
userType: userType,
userMajor: item1.userMajor
});
}
});
});
// 5. 提交到后端(保持原有逻辑不变)
const loading = ElLoading.service({ text: '提交中...', background: 'rgba(255,255,255,0.7)' });
const res = await designUserAdd({
list: arr,
projectId: currentProject.value?.id
});
if (res.code == 200) {
disabledForm.value = true;
loading.close();
ElMessage.success('提交成功');
} else {
ElMessage.error(res.msg || '提交失败');
}
} catch (error) {
ElMessage.error('请完善表单信息后再提交');
} finally {
// ElLoading.service().close();
}
};
/** 重置表单(适配新数据结构) */
const resetForm = () => {
if (leaveFormRef.value) {
leaveFormRef.value.resetFields();
// 重置为默认空状态1个专业分组每组1个空人员
form.designers = [createEmptyMajorGroup()];
form.reviewers = [createEmptyMajorGroup()];
ElMessage.info('表单已重置');
}
};
// 监听项目ID刷新数据
const listeningProject: WatchStopHandle = watch(
() => currentProject.value?.id,
() => {
getDeptAllUser(userStore.deptId).then(() => {
designUser();
});
}
);
// 页面生命周期
onUnmounted(() => {
listeningProject();
});
onMounted(() => {
getDeptAllUser(userStore.deptId).then(() => {
designUser();
});
});
</script>
<style lang="scss" scoped>
.appointment {
width: 70vw;
max-width: 1600px;
.el-select__wrapper {
width: 100% !important;
}
.el-button--small {
margin-bottom: 0;
}
.fonts {
.el-form-item--default .el-form-item__label {
font-size: 18px !important;
}
}
}
// 自定义动画
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fadeIn {
animation: fadeIn 0.3s ease-out forwards;
}
// 表单样式优化
::v-deep .el-form {
--el-form-item-margin-bottom: 0;
}
::v-deep .el-form-item {
margin-bottom: 0;
&__label {
font-weight: 500;
color: #4e5969;
}
&__content {
padding: 0;
}
}
::v-deep .el-select {
width: 100%;
.el-input__inner {
border-radius: 6px;
transition: all 0.3s ease;
}
&:hover .el-input__inner {
border-color: #66b1ff;
}
&.el-select-focus .el-input__inner {
border-color: #409eff;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}
}
::v-deep .el-button {
border-radius: 6px;
padding: 8px 16px;
&--primary {
background-color: #409eff;
border-color: #409eff;
&:hover {
background-color: #66b1ff;
border-color: #66b1ff;
}
}
&--success {
background-color: #67c23a;
border-color: #67c23a;
&:hover {
background-color: #85ce61;
border-color: #85ce61;
}
&:disabled {
background-color: #b3e099;
border-color: #b3e099;
}
}
&--danger {
background-color: #f56c6c;
border-color: #f56c6c;
&:hover {
background-color: #f78989;
border-color: #f78989;
}
&:disabled {
background-color: #ffcccc;
border-color: #ffbbbb;
cursor: not-allowed;
}
}
&--text {
color: #f56c6c;
&:hover {
color: #f78989;
background-color: rgba(245, 108, 108, 0.05);
}
}
}
// 响应式网格布局
.grid {
display: grid;
}
.grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
.md\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.gap-4 {
gap: 1rem;
}
// 适配小屏幕小于768px时垂直排列
@media (max-width: 768px) {
.appWidth {
width: 95vw;
}
::v-deep .el-form {
padding: 4px;
}
::v-deep .el-form-item__label {
width: 100px;
}
// 小屏幕下各列上下间距
::v-deep .el-col-xs-24 + .el-col-xs-24 {
margin-top: 12px;
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
<el-col :span="1.5">
<div class="box_btn">
<file-upload :limit="1" :uploadUrl="uploadUrl" :params="uploadParams" :on-upload-success="uploadFile" :fileType="[]">
<el-button type="primary" style="float: left">
<el-button type="primary" style="float: left" v-hasPermi="['design:collectFile:add']">
<el-icon size="small"><Upload /></el-icon>上传文件
</el-button>
</file-upload>
@ -17,7 +17,13 @@
</template>
<el-table :data="FileList" style="width: 100%" height="64vh">
<el-table-column type="index" align="center" label="序号" width="180" />
<el-table-column prop="fileName" align="center" label="文件名称" />
<el-table-column align="center" label="文件名称">
<template #default="scope">
<el-link :key="scope.row.fileName" :href="scope.row.fileUrl" target="_blank" type="primary" :underline="false">
{{ scope.row.fileName }}
</el-link>
</template>
</el-table-column>
<el-table-column label="流程状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="wf_business_status" :value="scope.row.status" />

View File

@ -14,7 +14,7 @@
<el-input v-model="queryParams.volumeNo" placeholder="请输入卷册号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['design:designChange:list']">搜索</el-button>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -44,7 +44,7 @@
<el-table-column label="卷册号" align="center" prop="volumeNo" width="150" />
<el-table-column label="流程状态" align="center">
<template #default="scope">
<dict-tag v-if="scope.row.fileId != null" :options="wf_business_status" :value="scope.row.status" />
<dict-tag v-if="scope.row.costEstimation > 0" :options="wf_business_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="变更文件" align="center" width="150">
@ -64,19 +64,16 @@
<dict-tag :options="design_change_reason_type" :value="scope.row.changeReason ? scope.row.changeReason.split(',') : []" />
</template>
</el-table-column>
<el-table-column label="图纸状态" align="center">
<template #default="scope">
<dict-tag v-if="scope.row.fileId != null" :options="wf_business_status" :value="scope.row.auditStatus" />
</template>
</el-table-column>
<el-table-column label="变更内容" align="center" prop="changeContent" width="150" />
<el-table-column label="创建时间" align="center" prop="createTime" width="150" />
<el-table-column label="备注" align="center" prop="remark" width="200" />
<el-table-column label="操作" align="center" fixed="right" width="300">
<template #default="scope">
<el-button
type="primary"
link
icon="Upload"
@click="handleAddChange(scope.row)"
v-if="(scope.row.status == 'finish' || scope.row.costEstimation == '0') && scope.row.auditStatus == 'draft'"
>上传</el-button
>
<el-button
type="success"
link
@ -86,14 +83,37 @@
@click="handleViewInfo(scope.row)"
>查看</el-button
>
<el-button type="success" link icon="View" v-hasPermi="['design:designChange:query']" @click="handleViewDetail(scope.row)"
>通知单</el-button
<el-button
type="primary"
v-if="scope.row.status == 'draft' && scope.row.costEstimation > 0"
link
icon="plus"
v-hasPermi="['design:designChange:query']"
@click="handleViewUpdate(scope.row)"
>审核通知单</el-button
>
<el-button
v-if="scope.row.status != 'draft'"
type="success"
link
icon="View"
v-hasPermi="['design:designChange:query']"
@click="handleViewDetail(scope.row)"
>查看通知单</el-button
>
<el-button
type="primary"
link
icon="Upload"
@click="handleAddChange(scope.row)"
v-if="(scope.row.status == 'finish' || scope.row.costEstimation == '0') && scope.row.auditStatus == 'draft'"
>上传图纸</el-button
>
<el-button
type="warning"
link
icon="View"
v-hasPermi="['design:designChange:query']"
v-hasPermi="['design:drawingreviewReceipts:list']"
v-if="scope.row.status != 'draft'"
@click="handleViewHistory(scope.row)"
>查看单据</el-button
@ -210,6 +230,17 @@ const handleAdd = () => {
});
};
/** 查看详情 */
const handleViewUpdate = (row) => {
proxy.$tab.closePage(proxy.$route);
proxy.$router.push({
path: `/approval/designChange/indexEdit`,
query: {
id: row.id,
type: 'update'
}
});
};
/** 查看详情 */
const handleViewDetail = (row) => {
proxy.$tab.closePage(proxy.$route);
proxy.$router.push({

View File

@ -3,19 +3,30 @@
<div class="max-w-4xl mx-auto">
<!-- 顶部按钮区域 -->
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
<approvalButton @submitForm="submitForm" @approvalVerifyOpen="approvalVerifyOpen"
@handleApprovalRecord="handleApprovalRecord" :buttonLoading="buttonLoading" :id="form.id"
:status="form.status" :pageType="routeParams.type" />
<approvalButton
@submitForm="submitForm"
@approvalVerifyOpen="approvalVerifyOpen"
@handleApprovalRecord="handleApprovalRecord"
:buttonLoading="buttonLoading"
:id="form.id"
:status="form.status"
:pageType="routeParams.type"
/>
</el-card>
<!-- 表单区域 -->
<el-card
class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
<h3 class="text-lg font-semibold text-gray-800">变更图纸信息</h3>
</div>
<div class="p-6">
<el-form ref="leaveFormRef" :disabled="routeParams.type === 'view' || form.status == 'waiting'" :model="form"
:rules="rules" label-width="100px" class="space-y-4">
<el-form
ref="leaveFormRef"
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
:model="form"
:rules="rules"
label-width="100px"
class="space-y-4"
>
<div class="grid grid-cols-1 gap-4">
<el-row>
<el-col :span="12">
@ -25,14 +36,32 @@
</el-col>
<el-col :span="12">
<el-form-item label="工程名称" prop="projectName">
<el-input v-model="form.projectName" placeholder="请输入工程名称" /> </el-form-item></el-col>
<el-input v-model="form.projectName" disabled placeholder="请输入工程名称" /> </el-form-item
></el-col>
<el-col :span="12">
<el-form-item label="原卷册号" prop="volumeNo">
<el-select id="projectSelect" v-model="form.volumeNo" placeholder="请选择原卷册号" clearable filterable
@change="handleSelect" style="width: 150px; margin-right: 20px">
<el-option v-for="project in volumeCatalogList" :key="project.volumeNumber"
:label="project.volumeNumber" :value="project.volumeNumber" />
</el-select> </el-form-item></el-col>
<el-select
id="projectSelect"
v-model="form.volumeNo"
placeholder="请选择原卷册号"
clearable
filterable
@change="handleSelect"
style="width: 150px; margin-right: 20px"
>
<el-option
v-for="project in volumeCatalogList"
:key="project.volumeNumber"
:label="project.volumeNumber"
:value="project.volumeNumber"
/>
</el-select>
<el-tooltip class="box-item" effect="dark" content="只有通过审核的蓝图才能选择" placement="top-start">
<el-icon size="22" class="no-inherit">
<QuestionFilled />
</el-icon>
</el-tooltip> </el-form-item
></el-col>
<el-col :span="12">
<el-form-item label="提出单位" prop="submitUnit">
<el-input v-model="form.submitUnit" placeholder="请输入提出单位" />
@ -45,16 +74,16 @@
</el-col>
<el-col :span="12">
<el-form-item label="提出日期" prop="submitDate">
<el-date-picker clearable v-model="form.submitDate" type="date" value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择提出日期">
</el-date-picker> </el-form-item></el-col>
<el-date-picker clearable v-model="form.submitDate" type="date" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择提出日期">
</el-date-picker> </el-form-item
></el-col>
<!-- <el-col :span="12">
<el-form-item label="卷册名称" prop="volumeName"> <el-input v-model="form.volumeName" placeholder="请输入卷册名称" /> </el-form-item
></el-col> -->
<el-col :span="12">
<el-form-item label="子项名称" prop="subName">
<el-input disabled v-model="form.extendDetail.subName" placeholder="请输入子项名称" />
</el-form-item></el-col>
<el-input disabled v-model="form.extendDetail.subName" placeholder="请输入子项名称" /> </el-form-item
></el-col>
<el-col :span="24">
<el-form-item label="原设计处置" prop="designDisposal">
<el-radio-group v-model="form.extendDetail.designDisposal" @change="handleRadio">
@ -62,7 +91,8 @@
<el-radio value="2" :disabled="!designId" size="large">原图保留部分修改</el-radio>
<el-radio value="3" size="large">原图保留补充设计</el-radio>
</el-radio-group>
</el-form-item></el-col>
</el-form-item></el-col
>
<el-col :span="24" v-if="form.extendDetail.designDisposal == 2">
<el-form-item label="保留文件" prop="saveFile">
<el-checkbox-group v-model="form.saveFile">
@ -70,17 +100,20 @@
{{ dict.fileName }}
</el-checkbox>
</el-checkbox-group>
</el-form-item></el-col>
</el-form-item></el-col
>
<el-col :span="12">
<el-form-item label="设计阶段" prop="designPhase">
<el-input v-model="form.extendDetail.designPhase" placeholder="请输入设计阶段" /> </el-form-item></el-col>
<el-input v-model="form.extendDetail.designPhase" placeholder="请输入设计阶段" /> </el-form-item
></el-col>
<el-col :span="24">
<el-form-item label="变更类别" prop="changeCategory">
<el-radio-group v-model="form.extendDetail.changeCategory">
<el-radio value="1" size="large">重大设计变更</el-radio>
<el-radio value="2" size="large">一般设计变更</el-radio>
</el-radio-group>
</el-form-item></el-col>
</el-form-item></el-col
>
<el-col :span="24">
<el-form-item label="实施程序" prop="ImpProcedure">
<el-radio-group v-model="form.extendDetail.ImpProcedure">
@ -88,14 +121,15 @@
<el-radio value="2" size="large">建设单位送原施工图审查机构审查建设主管部分备案后交付实施</el-radio>
<el-radio value="3" size="large">建设单位确认后交付实施</el-radio>
</el-radio-group>
</el-form-item></el-col>
</el-form-item></el-col
>
<el-col :span="12">
<el-form-item label="更改相关专业" prop="involvingProfessions">
<el-input v-model="form.extendDetail.involvingProfessions" placeholder="请输入更改相关专业" />
</el-form-item></el-col>
<el-input v-model="form.extendDetail.involvingProfessions" placeholder="请输入更改相关专业" /> </el-form-item
></el-col>
<el-col :span="24">
<el-form-item label="附图" prop="attachmentPic"> <image-upload v-model="form.attachmentPic"
:fileSize="100" /> </el-form-item></el-col>
<el-form-item label="附图" prop="attachmentPic"> <image-upload v-model="form.attachmentPic" :fileSize="100" /> </el-form-item
></el-col>
<el-col :span="24">
<el-form-item label="变更原因" prop="changeReason">
<el-checkbox-group v-model="form.changeReason">
@ -103,23 +137,27 @@
{{ dict.label }}
</el-checkbox>
</el-checkbox-group>
</el-form-item></el-col>
</el-form-item></el-col
>
<el-col :span="24">
<el-form-item label="变更内容" prop="changeContent">
<el-input v-model="form.changeContent" type="textarea" placeholder="请输入内容" />
</el-form-item></el-col>
<el-input v-model="form.changeContent" type="textarea" placeholder="请输入内容" /> </el-form-item
></el-col>
<el-col :span="12">
<el-form-item label="费用" prop="costEstimation">
<el-input v-model="form.costEstimation" type="number" placeholder="请输入费用" />
</el-form-item></el-col>
<el-input min="0" v-model="form.costEstimation" type="number" placeholder="请输入费用" /> </el-form-item
></el-col>
<el-col :span="24">
<el-form-item label="变更费用估算表" label-width="110px" prop="costEstimationFile">
<file-upload v-model="form.costEstimationFile" :fileSize="100" /> </el-form-item></el-col>
<file-upload v-model="form.costEstimationFile" :fileSize="100" /> </el-form-item
></el-col>
<!-- <el-col :span="24">
<el-form-item label="变更文件" prop="fileId"> <file-upload v-model="form.fileId" :fileSize="100" /> </el-form-item
></el-col> -->
<el-col :span="24"><el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" /> </el-form-item></el-col>
<el-col :span="24"
><el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" /> </el-form-item
></el-col>
</el-row>
</div>
</el-form>
@ -129,8 +167,14 @@
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
<approvalRecord ref="approvalRecordRef"></approvalRecord>
<!-- 流程选择对话框 -->
<el-dialog draggable v-model="dialogVisible.visible" :title="dialogVisible.title" :before-close="handleClose"
width="500" class="rounded-lg shadow-lg">
<el-dialog
draggable
v-model="dialogVisible.visible"
:title="dialogVisible.title"
:before-close="handleClose"
width="500"
class="rounded-lg shadow-lg"
>
<div class="p-4">
<p class="text-gray-600 mb-4">请选择要启动的流程</p>
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
@ -139,10 +183,12 @@
</div>
<template #footer>
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
<el-button @click="handleClose"
class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors">取消</el-button>
<el-button type="primary" @click="submitFlow()"
class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors">确认</el-button>
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
>取消</el-button
>
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
>确认</el-button
>
</div>
</template>
</el-dialog>
@ -208,7 +254,7 @@ const initFormData = {
id: undefined,
projectId: currentProject.value?.id,
formNo: undefined,
projectName: undefined,
projectName: currentProject.value?.name,
submitUnit: undefined,
specialty: undefined,
specialtyName: undefined,
@ -302,8 +348,11 @@ const getInfo = () => {
loading.value = true;
buttonLoading.value = false;
nextTick(async () => {
const res = await getDesignChange(routeParams.value.id);
let id = routeParams.value.id.split('_')[0];
const res = await getDesignChange(id);
Object.assign(form.value, res.data);
console.log(form.value);
if (form.value.changeReason.length > 0) {
form.value.changeReason = form.value.changeReason.split(',');
}
@ -328,24 +377,26 @@ const submitForm = (status1: string) => {
if (form.value.saveFile && form.value.saveFile.length > 0) {
saveFile = form.value.saveFile.join(',');
}
}
leaveFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
var res;
res = await addDesignChange({ ...form.value, changeReason, saveFile }).finally(() => (buttonLoading.value = false));
if (res.code == 200) {
if (form.value.costEstimation == '0') {
ElMessage.success('通知成功');
goBack();
leaveFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
var res;
res = await addDesignChange({ ...form.value, changeReason, saveFile }).finally(() => (buttonLoading.value = false));
if (res.code == 200) {
if (form.value.costEstimation == '0') {
ElMessage.success('通知成功');
goBack();
} else {
submit(status.value, res.data);
}
} else {
submit(status.value, res.data);
ElMessage.error(res.msg);
}
} else {
ElMessage.error(res.msg);
}
}
});
});
} else {
submit(status.value, form.value);
}
};
const submitFlow = async () => {
@ -383,14 +434,15 @@ const submitCallback = async () => {
};
//审批
const approvalVerifyOpen = async () => {
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
// submitVerifyRef.value.openDialog(routeParams.value.taskId);
// submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
submitVerifyRef.value.openDialog(routeParams.value.taskId);
};
// 图纸上传成功之后 开始提交
const route = useRoute();
const router = useRouter();
const submit = async (status, data) => {
form.value = data;
form.value.id = form.value.id + '_audit';
if (status === 'draft') {
buttonLoading.value = false;
proxy?.$modal.msgSuccess('暂存成功');

View File

@ -24,8 +24,8 @@
<el-input v-model="queryParams.documentName" placeholder="请输入资料名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['design:volumeCatalog:query']">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery" v-hasPermi="['design:volumeCatalog:query']">重置</el-button>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
@ -47,6 +47,7 @@
target="_blank"
type="primary"
:underline="false"
v-hasPermi="['design:volumeFileViewer:add']"
@click="handleBookFile(scope.row)"
>
{{ scope.row.fileName }}
@ -55,8 +56,10 @@
</el-table-column>
<el-table-column label="操作" align="center" prop="remark" width="300">
<template #default="scope">
<el-button link type="primary" icon="view" @click="handleViewHis(scope.row)">查阅记录</el-button>
<el-button type="warning" link icon="Download" @click="handleDownload(scope.row)"> 下载 </el-button>
<el-button link type="primary" icon="view" v-hasPermi="['design:drawing:list']" @click="handleViewHis(scope.row)">查阅记录</el-button>
<el-button type="warning" link icon="Download" v-hasPermi="['design:volumeFileViewer:add']" @click="handleDownload(scope.row)">
下载
</el-button>
</template>
</el-table-column>
</el-table>

View File

@ -36,7 +36,7 @@
</div>
</el-card>
<!-- 提交组件 -->
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
<submitVerify ref="submitVerifyRef" :businessId1="form.id" :task-variables="taskVariables" @submit-callback="submitCallback" />
<approvalRecord ref="approvalRecordRef"></approvalRecord>
<!-- 流程选择对话框 -->
<el-dialog
@ -253,13 +253,16 @@ const submitCallback = async () => {
};
//审批
const approvalVerifyOpen = async () => {
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
// submitVerifyRef.value.openDialog(routeParams.value.taskId);
// 判断是否还需要设计验证
if (form.value.isWindow) {
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
} else {
submitVerifyRef.value.openDialog(routeParams.value.taskId);
}
};
// 图纸上传成功之后 开始提交
const submit = async (status, data) => {
form.value = data;
form.value.id = routeParams.value.type == 'add' ? form.value.id + '_' : form.value.id.split('_')[0];
form.value.status = data.auditStatus ? data.auditStatus : data.status;
if (status === 'draft') {
buttonLoading.value = false;

View File

@ -11,12 +11,17 @@
<el-col :span="12">
<el-form-item label="编号" prop="num">
<!-- prop="num" 需与 rules 中键名一致 -->
<el-input v-model="formData.num" placeholder="请输入编号" />
<el-input v-model="formData.num" disabled placeholder="请输入编号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="专业" prop="professional">
<el-input v-model="formData.professional" placeholder="请输入专业" />
<el-form-item label="专业" prop="professionalName">
<el-input v-model="formData.professionalName" disabled placeholder="请输入专业" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="卷册" prop="volume">
<el-input v-model="formData.volume" disabled placeholder="请输入卷册" />
</el-form-item>
</el-col>
<el-col :span="12">
@ -24,14 +29,8 @@
<el-input v-model="formData.stage" placeholder="请输入设计阶段" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="卷册" prop="volume">
<el-input v-model="formData.volume" placeholder="请输入卷册" />
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 项目信息区域 -->
<div class="form-section">
<div class="section-title">
@ -54,7 +53,6 @@
</el-col>
</el-row>
</div>
<!-- 人员信息区域 -->
<div class="form-section">
<div class="section-title">
@ -65,56 +63,77 @@
<el-row :gutter="20" class="section-content">
<el-col :span="12">
<el-form-item label="设计人" prop="designer">
<el-input v-model="formData.designer" placeholder="请输入设计人" />
<el-input disabled v-model="formData.designerName" placeholder="请输入设计人" />
</el-form-item>
</el-col>
<el-col :span="12"></el-col>
<el-col :span="12">
<el-form-item label="校审人员" prop="proofreading">
<el-input v-model="formData.proofreading" placeholder="请输入校审人员" />
<el-input disabled v-model="formData.proofreading" placeholder="请输入校审人员" />
</el-form-item>
</el-col>
<!-- <el-col :span="12">
<el-form-item label="校审人员ID" prop="proofreadingId">
<el-input v-model="formData.proofreadingId" placeholder="请输入校审人员ID" />
</el-form-item>
</el-col> -->
<el-col :span="12">
<el-form-item label="校审时间" prop="proofreadingDate">
<el-date-picker v-model="formData.proofreadingDate" type="date" placeholder="选择校审时间" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" />
<el-date-picker
v-model="formData.proofreadingDate"
type="date"
disabled
placeholder="选择校审时间"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="审核人员" prop="audit">
<el-input v-model="formData.audit" placeholder="请输入审核人员" />
<el-input disabled v-model="formData.audit" placeholder="请输入审核人员" />
</el-form-item>
</el-col>
<!-- <el-col :span="12">
<el-form-item label="审核人员ID" prop="auditId">
<el-input v-model="formData.auditId" placeholder="请输入审核人员ID" />
</el-form-item>
</el-col> -->
<el-col :span="12">
<el-form-item label="审核时间" prop="auditDate">
<el-date-picker v-model="formData.auditDate" type="date" placeholder="选择审核时间" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" />
<el-date-picker
disabled
v-model="formData.auditDate"
type="date"
placeholder="选择审核时间"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="审定人员" prop="approve">
<el-input disabled v-model="formData.approve" placeholder="请输入审定人员" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="审定时间" prop="approveDate">
<el-date-picker
disabled
v-model="formData.approveDate"
type="date"
placeholder="选择审定时间"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="执行人员" prop="executor">
<el-input v-model="formData.executor" placeholder="请输入执行人员" />
<el-select
v-model="formData.executorId"
@change="changeExecutor"
placeholder="选择执行人员"
class="w-full transition-all duration-300 border-gray-300"
>
<el-option v-for="item in userList" :key="`user-${item.userId}`" :label="item.userName" :value="item.userId" />
</el-select>
<!-- <el-input v-model="formData.executor" placeholder="请输入执行人员" /> -->
</el-form-item>
</el-col>
<!-- <el-col :span="12">
<el-form-item label="执行人员ID" prop="executorId">
<el-input v-model="formData.executorId" placeholder="请输入执行人员ID" />
</el-form-item>
</el-col> -->
<el-col :span="12">
<el-form-item label="执行时间" prop="executorDate">
<el-date-picker v-model="formData.executorDate" type="date" placeholder="选择执行时间" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" />
<el-date-picker v-model="formData.executorDate" type="date" placeholder="选择执行时间" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
</el-row>
@ -151,17 +170,20 @@
<script setup name="ExamineForm" lang="ts">
import { ref, watch, reactive } from 'vue';
import { fillOutTheDesignVerificationForm, drawingreviewReceipts } from '@/api/design/drawingreview';
import type { FormInstance, FormRules } from 'element-plus';
import { dayjs, type FormInstance, type FormRules } from 'element-plus';
import { useUserStoreHook } from '@/store/modules/user';
import { computed } from 'vue';
import { subProjectListAll } from '@/api/design/drawingreview';
import { subProjectListAll, getDrawingreviewReceipts } from '@/api/design/drawingreview';
import { desUserList } from '@/api/design/appointment';
// 获取用户 store
const userStore = useUserStoreHook();
const userList = ref([]);
const userMap = new Map();
// 从 store 中获取当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
console.log(currentProject.value);
const subProjectList = ref([]);
const Drawingreview = ref({});
let subProjectMap = new Map();
// 定义表单数据类型
interface FormData {
@ -193,9 +215,9 @@ const rules: FormRules = {
num: [{ required: true, message: '请输入编号', trigger: 'blur' }],
professional: [{ required: true, message: '请输入专业', trigger: 'blur' }]
};
const userName = userStore.nickname;
// 表单数据 - 直接在组件内定义不再通过Props接收
const formData = reactive<FormData>({
const formData = ref({
num: '',
professional: '',
stage: '',
@ -228,8 +250,8 @@ watch(
(newVal) => {
if (newVal) {
// 根据实际项目结构调整赋值字段
formData.projectId = newVal.id || '';
formData.projectName = newVal.name || '';
formData.value.projectId = newVal.id || '';
formData.value.projectName = newVal.name || '';
}
},
{ immediate: true, deep: true }
@ -259,12 +281,12 @@ const resetFields = () => {
// 获取表单数据
const getFormData = (): FormData => {
return { ...formData };
return { ...formData.value };
};
// 设置表单数据
const setFormData = (data: Partial<FormData>) => {
Object.assign(formData, data);
Object.assign(formData.value, data);
};
// 提交表单
@ -279,12 +301,10 @@ const submit = async (businessId, cb) => {
background: 'rgba(0, 0, 0, 0.7)'
});
formData.subprojectName = subProjectMap.get(formData.subprojectId);
// formData.drawingreviewId = businessId;
formData.value.subprojectName = subProjectMap.get(formData.value.subprojectId);
console.log(businessId);
// businessId 设置 如果有下滑线去掉后面及下划线
formData.drawingreviewId = businessId.replace(/_/g, '');
const res = await drawingreviewReceipts(formData);
formData.value.drawingreviewId = businessId.replace(/_/g, '');
const res = await drawingreviewReceipts(formData.value);
if (res.code === 200) {
// 提交成功处理逻辑
console.log('提交成功');
@ -292,6 +312,52 @@ const submit = async (businessId, cb) => {
// 关闭
ElLoading.service().close();
};
// 获取单据
const getInfo = async (id) => {
// 获取单据
console.log(id);
await getDeptAllUser();
let res = await getDrawingreviewReceipts(id);
console.log(res);
formData.value = res.data;
console.log(formData);
// 设计人 名称 designerName iddesigner
// 校审人员 名称 proofreading id: proofreadingId 校审时间 proofreadingDate
// 审定人员 名称 approve idapproveId 审定时间 approveDate
// 审核人员 名称 audit idauditId 审核时间 auditDate
// userStore.nickname //用户名
// userStore.userId //用户id
if (formData.value.approve) {
} else if (formData.value.audit) {
// 说明流程在第三步
formData.value.approve = userStore.nickname;
formData.value.approveId = userStore.userId;
formData.value.approveDate = dayjs().format('YYYY-MM-DD');
} else if (formData.value.proofreading) {
// 说明流程在第二步
formData.value.audit = userStore.nickname;
formData.value.auditId = userStore.userId;
formData.value.auditDate = dayjs().format('YYYY-MM-DD');
} else if (formData.value.designerName) {
// 说明流程在第一步
formData.value.proofreading = userStore.nickname;
formData.value.proofreadingId = userStore.userId;
formData.value.proofreadingDate = dayjs().format('YYYY-MM-DD');
}
};
/** 获取当前设计用户 */
const getDeptAllUser = async () => {
const res = await desUserList({ projectId: currentProject.value?.id, userType: '2' });
userList.value = res.data || [];
for (let i = 0; i < userList.value.length; i++) {
userMap.set(userList.value[i].userId, userList.value[i].userName);
}
};
const changeExecutor = (val) => {
formData.value.executor = userMap.get(val);
formData.value.executorDate = dayjs().format('YYYY-MM-DD');
};
onMounted(() => {
getSubProject();
});
@ -301,7 +367,8 @@ defineExpose({
resetFields,
getFormData,
setFormData,
submit
submit,
getInfo
});
</script>

View File

@ -48,7 +48,7 @@
v-if="scope.row.status !== 'draft'"
icon="Edit"
@click="handleView(scope.row)"
v-hasPermi="['design:PrelimScheme:query']"
v-hasPermi="['design:prelimScheme:query']"
>查看流程</el-button
>
<el-button
@ -57,7 +57,7 @@
v-if="scope.row.status === 'draft'"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['design:PrelimScheme:edit']"
v-hasPermi="['design:prelimScheme:edit']"
>修改</el-button
>
<!-- <el-button
@ -109,7 +109,7 @@ const dialog = reactive<DialogOption>({
const initFormData: PrelimSchemeForm = {
id: undefined,
projectId: undefined,
projectId: currentProject.value?.id,
ossId: undefined,
fileName: undefined,
fileUrl: undefined,
@ -120,7 +120,8 @@ const data = reactive<PageData<PrelimSchemeForm, PrelimSchemeQuery>>({
queryParams: {
pageNum: 1,
pageSize: 10,
projectId: undefined,
projectId: currentProject.value?.id,
ossId: undefined,
fileName: undefined,
fileUrl: undefined,

View File

@ -173,8 +173,6 @@ const getInfo = () => {
const res = await getPrelimScheme(routeParams.value.id);
Object.assign(form.value, res.data);
form.value.file = res.data.ossId;
showFileList.value = false;
loading.value = false;
buttonLoading.value = false;
});
@ -188,11 +186,10 @@ const submitForm = async (status1: string) => {
if (form.value.id) {
if (!updateFileStatus.value) return proxy?.$modal.msgError('请上传图纸文件');
buttonLoading.value = true;
let data = { id: form.value.id, projectId: form.value.id, file: form.value.file };
if (form.value.file === form.value.ossId) {
let data = { id: form.value.id, projectId: form.value.projectId, file: form.value.file };
if (form.value.file === form.value.ossId && !isUpdateFile.value) {
data.file = '';
res = await updatePrelimScheme(data).finally(() => (buttonLoading.value = false));
if (res.code == 200) {
dialog.visible = false;
submit(status.value, form.value);
@ -286,10 +283,11 @@ const handleUploadSuccess = (list, res) => {
const fileStatus = ref(false);
const updateFileStatus = ref(true);
const isUpdateFile = ref(false); //记录是否在修改页面时是否有新上传的文件
const handleFileChange = (file, fileList) => {
if (form.value.id) {
updateFileStatus.value = true;
isUpdateFile.value = true; //记录是否在修改页面时是否有新上传的文件
}
fileStatus.value = true;
};
@ -297,6 +295,7 @@ const handleFileChange = (file, fileList) => {
const handleFileRemove = (file, fileList) => {
if (form.value.id) {
updateFileStatus.value = false;
isUpdateFile.value = false; //记录是否在修改页面时是否有新上传的文件
}
showFileList.value = true;

View File

@ -1,86 +1,172 @@
<template>
<div class="p-6 bg-gray-50">
<div
class="received mx-auto bg-white rounded-xl shadow-sm overflow-hidden transition-all duration-300 hover:shadow-md">
<div class="p-6 bg-gray-50 min-h-screen">
<div class="received mx-auto bg-white rounded-xl shadow-sm overflow-hidden transition-all duration-300 hover:shadow-md">
<!-- 表单标题区域 -->
<div class="bg-gradient-to-r from-blue-500 to-blue-600 text-white p-6">
<h2 class="text-2xl font-bold flex items-center"><i class="el-icon-user-circle mr-3"></i>收集资料清单</h2>
<p class="text-blue-100 mt-2 opacity-90">请填写相关资料信息</p>
</div>
<!-- 表单内容区域 -->
<el-form ref="mainFormRef" :model="form" :rules="mainRules" label-width="120px" class="p-6">
<el-form ref="mainFormRef" :model="form" :rules="mainRules" label-width="120px" class="p-6 md:p-8">
<!-- 基本信息区域 -->
<div class="bg-blue-50 p-4 rounded-lg mb-6">
<div class="bg-blue-50 p-4 rounded-lg mb-6 md:mb-8">
<h3 class="text-lg font-semibold text-blue-700 mb-4">基本信息</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<el-form-item label="收资人" prop="userId" class="mb-4">
<el-select :disabled="disabledAll" v-model="form.userId" placeholder="请选择收资人"
class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<el-form-item label="收资人" prop="userId" class="mb-0">
<el-select
:disabled="disabledAll"
v-model="form.userId"
placeholder="请选择收资人"
class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400"
>
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
<el-form-item label="专业" prop="user_major" class="mb-4">
<el-select :disabled="disabledAll" v-model="form.user_major" placeholder="请选择专业"
class="transition-all duration-300 border-gray-300"
:rules="{ required: true, message: '请选择专业', trigger: 'change' }">
<el-form-item label="专业" prop="user_major" class="mb-0">
<el-select
:disabled="disabledAll"
v-model="form.user_major"
placeholder="请选择专业"
class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400"
>
<el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="电话" prop="phone" class="mb-4">
<el-input :disabled="disabledAll" placeholder="请输入电话" v-model="form.phone" autocomplete="off" />
<el-form-item label="电话" prop="phone" class="mb-0">
<el-input :disabled="disabledAll" placeholder="请输入电话" v-model="form.phone" autocomplete="off" class="w-full" />
</el-form-item>
<el-form-item label="邮箱" prop="email" class="mb-4">
<el-input :disabled="disabledAll" placeholder="请输入邮箱" v-model="form.email" autocomplete="off" />
<el-form-item label="邮箱" prop="email" class="mb-0">
<el-input :disabled="disabledAll" placeholder="请输入邮箱" v-model="form.email" autocomplete="off" class="w-full" />
</el-form-item>
</div>
</div>
<!-- 资料文件区域 -->
<div class="mb-6">
<div class="flex items-center justify-between mb-4">
<div class="mb-8">
<div class="flex items-center justify-between mb-5">
<h3 class="text-lg font-semibold text-blue-700">资料文件清单</h3>
<el-button type="primary" size="small" @click="addDocumentItem" v-if="!disabledAll" icon="Plus"> 添加资料
<el-button type="primary" size="small" @click="addDocumentItem" v-if="!disabledAll" icon="Plus" class="transition-all hover:bg-blue-600">
添加资料
</el-button>
</div>
<el-form ref="documentsFormRef" :model="form" class="space-y-4">
<div v-for="(item, index) in form.documents" :key="item.id"
class="bg-gray-50 p-4 rounded-lg transition-all duration-200 hover:shadow-sm">
<div class="flex justify-between items-start mb-2">
<span class="text-sm font-medium text-gray-600">资料 {{ index + 1 }}</span>
<el-button type="text" size="small" text-color="#ff4d4f" @click="removeDocumentItem(index)"
icon="el-icon-delete" v-if="form.documents.length > 1 && !disabledAll">
<!-- 资料列表表单 -->
<el-form ref="documentsFormRef" :model="form" class="space-y-5">
<div
v-for="(item, index) in form.documents"
:key="item.id"
class="bg-gray-50 p-5 rounded-lg transition-all duration-200 hover:shadow-sm border border-gray-100"
>
<div class="flex justify-between items-center mb-4 pb-3 border-b border-gray-200">
<span class="text-sm font-medium text-gray-700">资料 {{ index + 1 }}</span>
<el-button
type="text"
size="small"
text-color="#ff4d4f"
@click="removeDocumentItem(index)"
icon="el-icon-delete"
v-if="form.documents.length > 1 && !disabledAll"
class="transition-all hover:text-red-600"
>
删除
</el-button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<el-form-item label="文件目录名称" :prop="`documents.${index}.catalogueName`"
:rules="[{ required: true, message: '请输入文件目录名称', trigger: 'blur' }]" class="mb-4">
<el-input :disabled="disabledAll" placeholder="请输入文件目录名称" v-model="item.catalogueName"
autocomplete="off" />
<div class="flex flex-col md:flex-row gap-5 items-stretch">
<el-form-item
label="文件目录名称"
:prop="`documents.${index}.catalogueName`"
:rules="[{ required: true, message: '请输入文件目录名称', trigger: 'blur' }]"
class="flex-1 min-w-[280px] mb-0"
>
<el-input :disabled="disabledAll" placeholder="请输入文件目录名称" v-model="item.catalogueName" autocomplete="off" class="w-full" />
</el-form-item>
<el-form-item label="备注" :prop="`documents.${index}.remark`" class="mb-4">
<el-input :disabled="disabledAll" placeholder="请输入备注" v-model="item.remark" autocomplete="off" />
<el-form-item
label="人员"
:prop="`documents.${index}.userId`"
:rules="[{ required: true, message: '请选择人员', trigger: 'blur' }]"
class="flex-1 min-w-[220px] mb-0"
>
<el-select
:disabled="disabledAll"
v-model="item.userId"
placeholder="请选择人员"
class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400"
>
<el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" />
</el-select>
</el-form-item>
<el-form-item label="备注" :prop="`documents.${index}.remark`" class="flex-1 min-w-[220px] mb-0">
<el-input :disabled="disabledAll" placeholder="请输入备注" v-model="item.remark" autocomplete="off" class="w-full" />
</el-form-item>
</div>
</div>
</el-form>
</div>
<!-- 操作按钮区域 -->
<div class="flex justify-center gap-4 mt-8">
<el-button type="primary" @click="submitForm" v-hasPermi="['design:collect:add']"
v-if="!form.id || form.status == 'draft'" size="large">确认提交</el-button>
<el-button type="primary" @click="update" v-hasPermi="['design:collect:query']"
v-show="form.id && form.status == 'draft'" icon="Edit" size="large">审核</el-button>
<el-button type="primary" @click="update" v-hasPermi="['design:collect:query']" v-show="form.status == 'back'"
size="large" icon="Edit">重新发起审核</el-button>
<el-button type="primary" @click="onView" v-hasPermi="['design:collect:query']"
v-show="form.id && form.status != 'draft'" icon="view" size="large">查看流程</el-button>
<el-button type="success" v-hasPermi="['design:collect:export']" @click="onLoad"
v-show="form.id && form.status != 'draft'" icon="Download" size="large">导出</el-button>
<!-- 操作按钮区域居中+间距优化 -->
<div class="flex flex-wrap justify-center gap-4 md:gap-6 mt-10">
<el-button
type="primary"
@click="submitForm"
v-hasPermi="['design:collect:add']"
v-if="!form.id || form.status == 'draft'"
size="large"
class="px-8 transition-all hover:bg-blue-600"
>
确认提交
</el-button>
<el-button
type="primary"
@click="update"
v-hasPermi="['design:collect:query']"
v-show="form.id && form.status == 'draft'"
icon="Edit"
size="large"
class="px-8 transition-all hover:bg-blue-600"
>
审核
</el-button>
<el-button
type="primary"
@click="update"
v-hasPermi="['design:collect:query']"
v-show="form.status == 'back'"
size="large"
icon="Edit"
class="px-8 transition-all hover:bg-blue-600"
>
重新发起审核
</el-button>
<el-button
type="primary"
@click="onView"
v-hasPermi="['design:collect:query']"
v-show="form.id && form.status != 'draft'"
icon="view"
size="large"
class="px-8 transition-all hover:bg-blue-600"
>
查看流程
</el-button>
<el-button
type="success"
v-hasPermi="['design:collect:export']"
@click="onLoad"
v-show="form.id && form.status != 'draft'"
icon="Download"
size="large"
class="px-8 transition-all hover:bg-green-600"
>
导出
</el-button>
</div>
</el-form>
</div>
@ -88,51 +174,59 @@
</template>
<script setup name="DataCollectionForm" lang="ts">
import { ref, reactive, computed, onMounted } from 'vue';
import { ref, reactive, computed, onMounted, onUnmounted, watch, getCurrentInstance } from 'vue';
import { useUserStoreHook } from '@/store/modules/user';
import { ElMessage, ElLoading } from 'element-plus';
import { ElMessage, ElLoading, FormRules } from 'element-plus';
import { systemUserList } from '@/api/design/appointment';
import { collectBatch, byProjectId, exportWord } from '@/api/design/received';
import { getUser } from '@/api/system/user';
// 用户状态管理
// 获取用户 store
import type { ComponentInternalInstance, ElFormInstance } from 'element-plus';
// 全局实例与状态管理
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userStore = useUserStoreHook();
// 从 store 中获取当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
const { des_user_major } = toRefs<any>(proxy?.useDict('des_user_major'));
const userId = computed(() => userStore.userId);
// 表单引用
const mainFormRef = ref();
// 用户列表
const userList = ref([]);
const userMap = new Map();
const disabledAll = ref(false);
// 表单数据
const mainFormRef = ref<ElFormInstance>();
const documentsFormRef = ref<ElFormInstance>();
// 数据定义
const userList = ref<any[]>([]);
const userMap = new Map<string, string>(); // 存储用户ID与昵称映射
const disabledAll = ref(false); // 表单是否全部禁用
// 表单核心数据
const form = reactive({
projectId: currentProject.value?.id,
userId: '', // 收资人
user_major: '', // 专业
phone: '', // 电话
email: '', // 邮箱
id: '',
status: '',
id: '', // 表单ID
status: '', // 表单状态
documents: [
{
id: Date.now(),
catalogueName: '', // 文件目录名称
remark: '' // 备注
remark: '', // 备注
userId: '' // 负责人员
}
] as Array<{
id: number;
catalogueName: string;
remark: string;
userId: string;
num?: number; // 序号(提交时用)
userName?: string; // 人员名称(提交时用)
}>
});
// 主表单验证规则
const mainRules = reactive({
userId: [{ required: true, message: '请输入收资人', trigger: 'blur' }],
userId: [{ required: true, message: '请选择收资人', trigger: 'blur' }],
user_major: [{ required: true, message: '请选择专业', trigger: 'change' }],
phone: [
{ required: true, message: '请输入电话', trigger: 'blur' },
@ -144,138 +238,160 @@ const mainRules = reactive({
]
});
// 添加资料项
/** 添加资料项 */
const addDocumentItem = () => {
form.documents.push({
id: Date.now(),
id: Date.now(), // 用时间戳保证ID唯一
catalogueName: '',
remark: ''
remark: '',
userId: ''
});
};
// 删除资料项
/** 删除资料项 */
const removeDocumentItem = (index: number) => {
if (form.documents.length <= 1) {
ElMessage.warning('至少需要保留一条资料记录');
return;
}
form.documents.splice(index, 1);
};
// 查询数据 再次回显
/** 回显项目对应的表单数据 */
const byProjectIdAll = async () => {
// 调用接口获取数据
const res = await byProjectId(currentProject.value?.id);
console.log(res);
form.documents = [
{
id: Date.now(),
catalogueName: '',
remark: ''
}
];
disabledAll.value = false;
if (res.code === 200 && res.data) {
const data = res.data;
// 回显基本信息
form.userId = data.userId || '';
form.user_major = data.userMajor || '';
form.phone = data.phone || '';
form.email = data.email || '';
form.id = data.id || '';
form.status = data.status || '';
if (form.status == 'finish') {
// 表单全部禁用
disabledAll.value = true;
}
// 回显资料文件列表
if (data.catalogueList && data.catalogueList.length > 0) {
// 清空现有列表
form.documents = [];
// 填充新数据
data.catalogueList.forEach((item: any, index: number) => {
form.documents.push({
id: item.id || Date.now() + index, // 确保id唯一
catalogueName: item.catalogueName || '',
remark: item.remark || ''
});
});
} else {
console.log(11111111);
// 如果没有资料,保持一个空项
form.documents = [
{
id: Date.now(),
catalogueName: '',
remark: ''
}
];
console.log(form.documents);
}
}
};
// 提交表单
const submitForm = async () => {
if (!mainFormRef.value) return;
try {
const valid = await mainFormRef.value.validate();
if (valid) {
// 这里可以添加提交逻辑
form.documents.map((item, i) => {
item.num = i + 1;
});
let body = {
desCollectBo: {
projectId: currentProject.value?.id,
userId: form.userId, // 收资人
userMajor: form.user_major, // 专业
id: form.id,
phone: form.phone, // 电话
email: form.email, // 邮箱
userName: userMap.get(form.userId)
},
catalogueList: form.documents
};
let res = await collectBatch(body);
if (res.code == 200) {
byProjectIdAll();
ElMessage.success('表单提交成功');
} else {
ElMessage.success(res.msg);
const res = await byProjectId(currentProject.value?.id);
// 重置表单默认值
form.documents = [
{
id: Date.now(),
catalogueName: '',
remark: '',
userId: ''
}
];
disabledAll.value = false;
if (res.code == 200 && res.data) {
const data = res.data;
// 回显基本信息
form.userId = data.userId || '';
form.user_major = data.userMajor || '';
form.phone = data.phone || '';
form.email = data.email || '';
form.id = data.id || '';
form.status = data.status || '';
// 已完成状态禁用所有输入
if (form.status === 'finish') {
disabledAll.value = true;
}
// 回显资料列表
if (data.catalogueList && data.catalogueList.length > 0) {
form.documents = data.catalogueList.map((item: any, index: number) => ({
id: item.id || Date.now() + index, // 确保ID唯一
catalogueName: item.catalogueName || '',
remark: item.remark || '',
userId: item.userId || ''
}));
}
}
console.log(form);
} catch (error) {
ElMessage.error('请完善表单信息后再提交');
ElMessage.error('获取表单数据失败,请刷新重试');
console.error('数据回显错误:', error);
}
};
// 重置表单
/** 提交表单 */
const submitForm = async () => {
if (!mainFormRef.value) return;
try {
// 先验证主表单
await mainFormRef.value.validate();
// 再验证资料列表表单(如果存在)
if (documentsFormRef.value) {
await documentsFormRef.value.validate();
}
// 处理提交数据(补充序号和人员名称)
const submitDocuments = form.documents.map((item, i) => ({
...item,
num: i + 1,
userName: userMap.get(item.userId) || ''
}));
const submitData = {
desCollectBo: {
projectId: currentProject.value?.id,
userId: form.userId,
userMajor: form.user_major,
id: form.id,
phone: form.phone,
email: form.email,
userName: userMap.get(form.userId) || ''
},
catalogueList: submitDocuments
};
// 调用接口提交
const res = await collectBatch(submitData);
if (res.code === 200) {
ElMessage.success('表单提交成功');
byProjectIdAll(); // 重新拉取最新数据
} else {
ElMessage.warning(res.msg || '提交失败,请重试');
}
} catch (error) {
ElMessage.error('请完善表单必填信息后再提交');
console.error('表单验证失败:', error);
}
};
/** 重置表单 */
const resetForm = () => {
if (mainFormRef.value) {
mainFormRef.value.resetFields();
// form表单数据重置
form.userId = '';
form.user_major = '';
form.phone = '';
form.email = '';
form.id = '';
form.status = '';
}
// 重置资料列表,保留一个空项
// 重置资料列表为1条空记录
form.documents = [
{
id: Date.now(),
catalogueName: '',
remark: ''
remark: '',
userId: ''
}
];
};
/** 查询当前部门的所有用户 */
const getDeptAllUser = async (deptId: any) => {
/** 获取当前部门的所有用户 */
const getDeptAllUser = async (deptId: string | number) => {
try {
const res = await systemUserList({ deptId });
// 实际项目中使用接口返回的数据
userList.value = res.rows;
userList.value = res.rows || [];
// 构建用户ID-昵称映射
userList.value.forEach((user) => {
userMap.set(user.userId, user.nickName);
});
} catch (error) {
ElMessage.error('获取用户列表失败');
ElMessage.error('获取用户列表失败,请刷新重试');
console.error('用户列表获取错误:', error);
}
};
/** 跳转审核页面 */
const update = () => {
proxy.$tab.closePage(proxy.$route);
proxy.$router.push({
proxy?.$tab.closePage(proxy?.$route);
proxy?.$router.push({
path: `/approval/received/indexEdit`,
query: {
id: form.id,
@ -283,9 +399,11 @@ const update = () => {
}
});
};
/** 跳转流程查看页面 */
const onView = () => {
proxy.$tab.closePage(proxy.$route);
proxy.$router.push({
proxy?.$tab.closePage(proxy?.$route);
proxy?.$router.push({
path: `/approval/received/indexEdit`,
query: {
id: form.id,
@ -293,96 +411,158 @@ const onView = () => {
}
});
};
/** 获取当前用户详情 */
/** 获取当前用户详情(回显个人信息) */
const getUserDetail = async () => {
try {
const res = await getUser(userId.value);
// userInfo.value = res.data.user;
form.userId = res.data.user.userId;
form.phone = res.data.user.phonenumber;
form.email = res.data.user.email;
if (res.data?.user) {
form.userId = res.data.user.userId;
form.phone = res.data.user.phonenumber || '';
form.email = res.data.user.email || '';
}
} catch (err) {
ElMessage.error('获取用户信息失败');
ElMessage.error('获取个人信息失败,部分字段需手动填写');
console.error('用户详情获取错误:', err);
}
};
// 页面挂载时初始化数据
onMounted(() => {
// 可以在这里添加初始化逻辑
getUserDetail();
getDeptAllUser(userStore.deptId).then(() => {
byProjectIdAll();
});
});
/** 导出文件 */
const onLoad = async () => {
// 导出接口
proxy?.download(
'design/collect/exportWord',
{
id: form.id
},
`收资清单.zip`
);
if (!form.id) {
ElMessage.warning('请先保存表单再导出');
return;
}
try {
proxy?.download('design/collect/exportWord', { id: form.id }, `收资清单_${new Date().getTime()}.doc`);
} catch (error) {
ElMessage.error('导出失败,请重试');
console.error('文件导出错误:', error);
}
};
//监听项目id刷新数据
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
getUserDetail();
/** 页面挂载初始化 */
onMounted(() => {
// 先获取当前用户信息,再获取部门用户列表,最后回显表单数据
getUserDetail().then(() => {
getDeptAllUser(userStore.deptId).then(() => {
byProjectIdAll();
});
});
});
/** 监听项目切换,刷新数据 */
const listeningProject = watch(
() => currentProject.value?.id,
(newId, oldId) => {
if (newId !== oldId) {
resetForm();
form.projectId = newId;
getUserDetail().then(() => {
getDeptAllUser(userStore.deptId).then(() => {
byProjectIdAll();
});
});
}
}
);
/** 页面卸载清理监听 */
onUnmounted(() => {
listeningProject();
});
</script>
<style lang="scss">
<style lang="scss" scoped>
// 主容器样式
.received {
width: 90%;
max-width: 1000px;
width: 95%;
max-width: 1200px;
margin-top: 20px;
margin-bottom: 40px;
}
// 全局样式调整,使界面更柔和
// 自定义滚动条(优化长列表体验)
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-thumb {
background-color: #e5e7eb;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background-color: #d1d5db;
}
// Element 组件样式覆盖(统一风格)
::v-deep .el-input__inner,
::v-deep .el-select__input {
border-radius: 6px;
border-color: #dcdfe6;
transition: all 0.2s ease;
::v-deep .el-select__input,
::v-deep .el-select-dropdown__item {
border-radius: 6px !important;
border-color: #dcdfe6 !important;
transition: all 0.2s ease !important;
}
::v-deep .el-input__inner:focus,
::v-deep .el-select__input:focus {
border-color: #409eff;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
border-color: #409eff !important;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2) !important;
outline: none !important;
}
::v-deep .el-button {
border-radius: 6px;
transition: all 0.2s ease;
::v-deep .el-form-item {
margin-bottom: 0 !important;
}
::v-deep .el-form-item__label {
font-weight: 500;
color: #606266;
font-weight: 500 !important;
color: #606266 !important;
padding-right: 12px !important;
}
// 响应式调整
@media (max-width: 768px) {
.received {
width: 95%;
}
::v-deep .el-button--primary {
background-color: #409eff !important;
border-color: #409eff !important;
}
::v-deep .el-form-item {
margin-bottom: 16px;
::v-deep .el-button--primary:hover {
background-color: #3390e0 !important;
border-color: #3390e0 !important;
}
::v-deep .el-button--success {
background-color: #52c41a !important;
border-color: #52c41a !important;
}
::v-deep .el-button--success:hover {
background-color: #47b811 !important;
border-color: #47b811 !important;
}
// 响应式适配(小屏幕调整)
@media (max-width: 768px) {
.p-6.md\:p-8 {
padding: 4px !important;
}
::v-deep .el-form-item__label {
width: 100px;
width: 100px !important;
font-size: 14px !important;
}
.flex.flex-col.md\:flex-row.gap-5 {
gap: 3px !important;
}
.el-button--large {
padding: 8px 16px !important;
font-size: 14px !important;
}
.bg-blue-50.p-4 {
padding: 15px !important;
}
}
</style>

View File

@ -8,7 +8,7 @@
<el-input v-model="queryParams.fileName" placeholder="请输入文件名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" v-hasPermi="['design:scheme:add']" @click="handleQuery">搜索</el-button>
<el-button type="primary" icon="Search" v-hasPermi="['design:scheme:list']" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -42,15 +42,7 @@
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button
link
type="primary"
v-if="scope.row.status !== 'draft'"
icon="Edit"
@click="handleView(scope.row)"
v-hasPermi="['design:PrelimScheme:query']"
>查看流程</el-button
>
<el-button link type="primary" v-if="scope.row.status !== 'draft'" icon="Edit" @click="handleView(scope.row)">查看流程</el-button>
<el-button
link
type="primary"

View File

@ -31,7 +31,11 @@
>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<el-form-item label="设计方案" prop="fileUrl" class="mb-2">
<el-link v-if="form.fileUrl" :href="form.fileUrl" target="_blank" type="primary" :underline="false">
{{ form.fileName }}
</el-link>
<file-upload
v-else
:limit="1"
:fileType="['pdf']"
:fileSize="100"
@ -181,8 +185,6 @@ const getInfo = () => {
const res = await getScheme(routeParams.value.id);
Object.assign(form.value, res.data);
form.value.file = res.data.ossId;
showFileList.value = false;
loading.value = false;
buttonLoading.value = false;
});
@ -198,7 +200,7 @@ const submitForm = async (status1: string) => {
buttonLoading.value = true;
let data = { id: form.value.id, projectId: form.value.id, file: form.value.file };
if (form.value.file === form.value.ossId) {
if (form.value.file === form.value.ossId && !isUpdateFile.value) {
data.file = '';
res = await updateScheme(data).finally(() => (buttonLoading.value = false));
if (res.code == 200) {
@ -294,10 +296,11 @@ const handleUploadSuccess = (list, res) => {
};
const fileStatus = ref(false);
const updateFileStatus = ref(true);
const isUpdateFile = ref(false);
const handleFileChange = (file, fileList) => {
if (form.value.id) {
updateFileStatus.value = true;
isUpdateFile.value = true;
}
fileStatus.value = true;
};
@ -305,6 +308,7 @@ const handleFileChange = (file, fileList) => {
const handleFileRemove = (file, fileList) => {
if (form.value.id) {
updateFileStatus.value = false;
isUpdateFile.value = false;
}
showFileList.value = true;

View File

@ -8,7 +8,7 @@
<el-input v-model="queryParams.subContent" placeholder="请输入分包内容" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['design:subcontract:add']">搜索</el-button>
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['design:subcontract:list']">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>

View File

@ -29,14 +29,17 @@
class="space-y-4"
>
<el-form-item label="图纸文件" prop="fileId" class="mb-2 md:col-span-2">
<el-input v-model="form.fileName" disabled placeholder="图纸名称" />
<el-link v-if="form.fileUrl" :href="form.fileUrl" target="_blank" type="primary" :underline="false">
{{ form.fileName }}
</el-link>
<!-- <el-input v-model="form.fileName" disabled placeholder="图纸名称" /> -->
</el-form-item>
</el-form>
</div>
</div>
</el-card>
<!-- 提交组件 -->
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
<submitVerify ref="submitVerifyRef" :businessId1="form.id" :task-variables="taskVariables" @submit-callback="submitCallback" />
<approvalRecord ref="approvalRecordRef"></approvalRecord>
<!-- 流程选择对话框 -->
<el-dialog
@ -96,7 +99,7 @@ const dialogVisible = reactive<DialogOption>({
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
//审批记录组件
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
//按钮组件
//按钮组件 approvalReadonly =ref(false);
const flowCodeOptions = [
{
value: currentProject.value?.id + '_bpDesignFile',
@ -123,7 +126,8 @@ const initFormData = {
fileUrl: undefined,
status: undefined,
originalName: undefined,
fileVoList: []
fileVoList: [],
auditStatus: undefined
};
const data = reactive({
form: { ...initFormData },
@ -198,8 +202,14 @@ const submitCallback = async () => {
};
//审批
const approvalVerifyOpen = async () => {
// 图纸评审验证
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
// 图纸评审验证 判断是否需要设计验证
if (form.value.isWindow) {
console.log(routeParams.value.businessId);
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
} else {
submitVerifyRef.value.openDialog(routeParams.value.taskId);
}
};
const submit = async (status, data) => {
form.value = data;

View File

@ -75,44 +75,6 @@
资料名称: {{ info.projectName || '未定义' }} | 卷册号: {{ info.volumeNumber || '未定义' }}
</p>
</div>
<!-- 基本信息区域 - 缩小间隔增强label与内容区分 -->
<div class="p-3 md:p-4 border-b border-gray-100 dark:border-gray-700/50">
<h3 class="text-base md:text-lg font-semibold mb-2 flex items-center text-gray-800 dark:text-gray-200">
<el-icon style="margin-right: 10px" :size="24" color="#409EFF">
<Document />
</el-icon>
基本信息
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 md:gap-3">
<InfoItem label="项目名称" value="projectName" :data="info" />
<InfoItem label="资料名称" value="documentName" :data="info" />
<InfoItem label="卷册号" value="volumeNumber" :data="info" />
<InfoItem label="设计子项名称" value="designSubitem" :data="info" />
<InfoItem label="专业名称" value="specialtyName" :data="info" />
<InfoItem label="文件格式" value="fileType" :data="info" />
</div>
</div>
<!-- 人员信息区域 -->
<div class="p-3 md:p-4 border-b border-gray-100 dark:border-gray-700/50">
<h3 class="text-base md:text-lg font-semibold mb-2 flex items-center text-gray-800 dark:text-gray-200">
<el-icon style="margin-right: 10px" :size="24" color="#409EFF">
<Document />
</el-icon>
人员信息
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-2 md:gap-3">
<InfoItem label="负责人" value="principal" :data="info" />
<InfoItem label="设计人员" value="principalName" :data="info" />
<InfoItem label="审核人员" value="reviewerName" :data="info" />
<InfoItem label="创建时间" value="createTime" :data="info" />
</div>
</div>
<!-- 状态信息区域 -->
<div class="p-3 md:p-4">
<h3 class="text-base md:text-lg font-semibold mb-2 flex items-center text-gray-800 dark:text-gray-200">
@ -150,13 +112,13 @@
</div>
</div>
<div class="info-item">
<!-- <div class="info-item">
<span class="info-label">文件大小</span>
<div class="info-value mt-0.5 flex items-center">
<i class="fa fa-hdd-o text-gray-400 dark:text-gray-500 mr-1.5"></i>
{{ info.fileSize || '未知' }}
</div>
</div>
</div> -->
<div class="info-item">
<span class="info-label">更新时间</span>
@ -189,6 +151,42 @@
</div>
</div>
</div>
<!-- 基本信息区域 - 缩小间隔增强label与内容区分 -->
<div class="p-3 md:p-4 border-b border-gray-100 dark:border-gray-700/50">
<h3 class="text-base md:text-lg font-semibold mb-2 flex items-center text-gray-800 dark:text-gray-200">
<el-icon style="margin-right: 10px" :size="24" color="#409EFF">
<Document />
</el-icon>
基本信息
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 md:gap-3">
<InfoItem label="项目名称" value="projectName" :data="info" />
<InfoItem label="资料名称" value="documentName" :data="info" />
<InfoItem label="卷册号" value="volumeNumber" :data="info" />
<InfoItem label="设计子项名称" value="designSubitem" :data="info" />
<InfoItem label="专业名称" value="specialtyName" :data="info" />
<InfoItem label="文件格式" value="fileType" :data="info" />
</div>
</div>
<!-- 人员信息区域 -->
<div class="p-3 md:p-4 border-b border-gray-100 dark:border-gray-700/50">
<h3 class="text-base md:text-lg font-semibold mb-2 flex items-center text-gray-800 dark:text-gray-200">
<el-icon style="margin-right: 10px" :size="24" color="#409EFF">
<Document />
</el-icon>
人员信息
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-2 md:gap-3">
<InfoItem label="负责人" value="principal" :data="info" />
<InfoItem label="设计人员" value="principalName" :data="info" />
<InfoItem label="审核人员" value="reviewerName" :data="info" />
<InfoItem label="创建时间" value="createTime" :data="info" />
</div>
</div>
</div>
</main>

View File

@ -39,9 +39,12 @@
:file-size="50"
:onUploadSuccess="handleUploadSuccess"
>
<el-button type="warning" plain icon="Upload">导入</el-button>
<el-button v-hasPermi="['design:volumeCatalog:importData']" type="warning" plain icon="Upload">导入</el-button>
</file-upload>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Download" @click="exportFile">导出模版</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
@ -52,7 +55,9 @@
<el-table-column label="子项名称" align="center" prop="designSubitem" />
<el-table-column label="设计状态" align="center" prop="designState">
<template #default="scope">
<dict-tag :options="design_state" :value="scope.row.designState" />
<el-tag type="primary" v-if="scope.row.designState == '2'">未出图</el-tag>
<el-tag type="success" v-if="scope.row.designState == '1'">已出图</el-tag>
<!-- <dict-tag :options="design_state" :value="scope.row.designState" /> -->
</template>
</el-table-column>
<el-table-column label="专业" align="center" prop="specialtyName"> </el-table-column>
@ -60,7 +65,9 @@
<el-table-column label="计划出图时间" align="center" prop="plannedCompletion" width="200" />
<el-table-column label="图纸文件" align="center" prop="remark" width="150">
<template #default="scope">
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['design:volumeFile:query']">查看文件</el-button>
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['design:volumeCatalog:listFile']"
>查看文件</el-button
>
</template>
</el-table-column>
<el-table-column label="外部意见" align="center">
@ -82,7 +89,9 @@
v-hasPermi="['design:volumeFile:add']"
>上传图纸</el-button
>
<el-button link type="primary" icon="Upload" @click="handleOpinion(scope.row)">外部意见</el-button>
<el-button link type="primary" v-hasPermi="['design:volumeFile:edit']" icon="Upload" @click="handleOpinion(scope.row)"
>外部意见</el-button
>
</template>
</el-table-column>
</el-table>
@ -532,7 +541,6 @@ const onSubmit = async () => {
buttonLoading.value = false;
}
};
/** 删除按钮操作 */
const handleDelete = async (row?: VolumeCatalogVO) => {
const _ids = row?.design || ids.value;
@ -607,6 +615,24 @@ const getVolumeFileList = async (type) => {
fileList.value = res.rows;
}
};
const exportFile = () => {
// 导出模版文件
try {
// 创建a标签
const link = document.createElement('a');
// 设置PDF文件路径 - 相对于public目录
link.href = '/catalog.xlsx';
// 设置下载后的文件名
link.download = '设计出图计划导入模版.xlsx';
// 触发点击
document.body.appendChild(link);
link.click();
// 清理
document.body.removeChild(link);
} catch (error) {
alert('下载失败,请重试');
}
};
// 切换
const handleClick = (val) => {
getVolumeFileList(val.props.name);

View File

@ -20,16 +20,12 @@
</div>
<div class="p-6">
<div class="grid grid-cols-1 gap-4">
<el-form
ref="leaveFormRef"
:disabled="routeParams.type === 'view' || form.auditStatus == 'waiting'"
:model="form"
:rules="rules"
label-width="100px"
class="space-y-4"
>
<el-form ref="leaveFormRef" :model="form" :rules="rules" label-width="100px" class="space-y-4">
<el-form-item label="图纸文件" prop="fileId" class="mb-2 md:col-span-2">
<el-input v-model="form.fileName" disabled placeholder="图纸名称" />
<!-- <el-input v-model="form.fileName" disabled placeholder="图纸名称" /> -->
<el-link :href="form.fileUrl" target="_blank" type="primary" :underline="false">
{{ form.fileName }}
</el-link>
</el-form-item>
</el-form>
</div>
@ -199,7 +195,7 @@ const submitCallback = async () => {
//审批
const approvalVerifyOpen = async () => {
// 图纸评审验证
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
submitVerifyRef.value.openDialog(routeParams.value.taskId);
};
const submit = async (status, data) => {
form.value = data;

View File

@ -46,6 +46,23 @@
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['formalities:listOfFormalities:add']">新增</el-button>
<span style="margin-left: 10px"
><el-tooltip class="box-item" effect="dark" content="从原有模板列表选择新增" placement="top">
<el-icon color="#409efc"><WarningFilled /></el-icon> </el-tooltip
></span>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="addTemplate()" v-hasPermi="['formalities:formalitiesAreConsolidated:addFormalities']"
>新增数据</el-button
>
<span style="margin-left: 10px">
<el-tooltip class="box-item" effect="dark" content="创建新模板并添加数据" placement="top">
<el-icon color="#409efc"><WarningFilled /></el-icon>
</el-tooltip>
</span>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
@ -64,7 +81,7 @@
<el-table v-loading="loading" :data="formalitiesAreConsolidatedList" @selection-change="handleSelectionChange" row-key="id" default-expand-all>
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="手续办理清单模板父级" align="center" prop="formalitiesPname" /> -->
<el-table-column label="手续办理清单模板" align="center" prop="formalitiesName" />
<el-table-column label="手续办理清单" align="center" prop="formalitiesName" />
<el-table-column label="计划开始时间" align="center" prop="planTheStartTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.planTheStartTime, '{y}-{m}-{d}') }}</span>
@ -213,6 +230,54 @@
</span>
</template>
</el-dialog>
<el-dialog title="新增合规性手续合账" v-model="templateVisbile" width="450">
<el-form-item label="合规性手续模板">
<el-cascader
v-model="tempValue"
:options="tempTreeList"
:props="{
multiple: true,
value: 'id',
label: 'name',
disabled: (node: any) => {
return (node.pid == 0 && !node.children.length) || node.status == 1; // 有 parent 的是二级,没有 parent 的是一级,禁用一级
}
}"
/>
<div style="margin-left: 10px; display: flex; justify-content: center; align-items: center">
<el-tooltip class="box-item" effect="dark" content="列表上已选择得模版不可再选" placement="top">
<el-icon><WarningFilled /></el-icon>
</el-tooltip>
</div>
</el-form-item>
<template #footer>
<span>
<el-button @click="templateVisbile = false">取消</el-button>
<el-button type="primary" @click="setTemp">确定</el-button>
</span>
</template>
</el-dialog>
<!-- 添加或修改手续办理清单模板对话框 -->
<el-dialog title="添加手续办理清单" v-model="tempDialogVisible" width="500px" append-to-body @close="templateCancel">
<el-form ref="listOfFormalitiesFormRef" :model="formTemplate" label-width="80px">
<el-form-item label="父级" prop="formalitiesPid" :rules="[{ required: true, message: '请选择父级', trigger: 'blur' }]">
<el-select v-model="formTemplate.formalitiesPid" placeholder="请选择父级">
<el-option label="根目录" value="0" />
<el-option v-for="item in listOfFormalitiesList" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="名称" prop="formalitiesName" :rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]">
<el-input v-model="formTemplate.formalitiesName" placeholder="请输入名称" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitFormTemplate"> </el-button>
<el-button @click="templateCancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
@ -225,14 +290,18 @@ import {
updateFormalitiesAreConsolidated,
listFormalitiesAnnex,
delFormalitiesAnnex,
editStatus
editStatus,
getTemplateTreeList
} from '@/api/formalities/formalitiesAreConsolidated';
import { listListOfFormalities, addFormalities } from '@/api/formalities/listOfFormalities';
import {
FormalitiesAreConsolidatedVO,
FormalitiesAreConsolidatedQuery,
FormalitiesAreConsolidatedForm
} from '@/api/formalities/formalitiesAreConsolidated/types';
import { useUserStoreHook } from '@/store/modules/user';
import { WarningFilled } from '@element-plus/icons-vue';
const fileVisible = ref(false);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 获取用户 store
@ -261,6 +330,7 @@ const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const file = ref(null);
const fileParams = reactive({
pageNum: 1,
@ -272,6 +342,8 @@ const statusForm = ref({
projectId: currentProject.value?.id,
processingStatus: undefined
});
const templateVisbile = ref(false);
const tempTreeList = ref([]);
const initFormData: FormalitiesAreConsolidatedForm = {
id: undefined,
@ -307,6 +379,8 @@ const data = reactive<PageData<FormalitiesAreConsolidatedForm, FormalitiesAreCon
const { queryParams, form, rules } = toRefs(data);
const tempValue = ref(null);
/** 查询合规性手续合账列表 */
const getList = async () => {
loading.value = true;
@ -367,6 +441,71 @@ const handleUpdate = async (row?: FormalitiesAreConsolidatedVO) => {
dialog.title = '修改合规性手续合账';
};
//新增
const handleAdd = async () => {
tempValue.value = null;
const res = await getTemplateTreeList({ projectId: currentProject.value.id });
tempTreeList.value = res.data;
templateVisbile.value = true;
};
const tempDialogVisible = ref(false);
const formTemplate: any = ref({
formalitiesPid: '',
formalitiesName: ''
});
const listOfFormalitiesList: any = ref([]);
//新增模版
const addTemplate = async () => {
tempDialogVisible.value = true;
const res = await listListOfFormalities();
listOfFormalitiesList.value = res.data;
};
//确定信息
const submitFormTemplate = async () => {
const params = {
projectId: currentProject.value.id,
addBusFormalitiesAreConsolidatedBo: {
...formTemplate.value
}
};
const res = await addFormalities(params);
if (res.code == 200) {
proxy?.$modal.msgSuccess('操作成功');
templateCancel();
getList();
}
};
//取消
const templateCancel = () => {
tempDialogVisible.value = false;
formTemplate.value.formalitiesPid = '';
formTemplate.value.formalitiesName = '';
};
// 选择模板
const setTemp = async () => {
// form.value.formalitiesPid = tempValue.value[tempValue.value.length - 1];
if (!tempValue.value || !tempValue.value.length) {
proxy?.$modal.msgWarning('请选择模板');
return;
}
let addBusFormalitiesAreConsolidatedBos = tempValue.value.map((item) => {
return {
formalitiesId: item[1],
formalitiesPid: item[0]
};
});
const data = {
addBusFormalitiesAreConsolidatedBos,
projectId: currentProject.value.id
};
const res = await addFormalitiesAreConsolidated(data);
if (res.code == 200) {
proxy?.$modal.msgSuccess('操作成功');
templateVisbile.value = false;
getList();
}
};
/** 上传按钮操作 */
const handleUpload = (row) => {
form.value.id = row.id;

View File

@ -1,6 +1,5 @@
<template>
<formalitiesAreConsolidated ref="formalitiesAreConsolidatedRef" class="overlay" v-if="showFormalitiesAreConsolidated" />
<div class="p-2" v-else>
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">

View File

@ -23,7 +23,7 @@ const props = defineProps({
},
// 数值
value: {
type: Number,
type: Number || String,
default: 205805.17
},
// 单位

View File

@ -147,14 +147,21 @@ const initEcharts = () => {
},
tooltip: {
trigger: 'item',
formatter: (params: any) => {
// 自定义提示框内容,显示更多项目信息
const data = params.data;
return `
<div style="font-weight: bold;">${data.name}</div>
<div>地点:${data.projectSite}</div>
<div>经纬度:${data.value[0].toFixed(6)}, ${data.value[1].toFixed(6)}</div>
`;
backgroundColor: 'rgba(3, 26, 52, 0.8)',
borderColor: '#1e3a6e',
textStyle: {
color: '#fff'
},
formatter: function (params: any) {
if (params.data) {
// 处理散点数据
const data = params.data;
return `
<div style="font-weight: bold;">${data.name}</div>
<div>地点:${data.projectSite}</div>
<div>经纬度:${data.value[0].toFixed(6)}, ${data.value[1].toFixed(6)}</div>
`;
}
}
},
series: [
@ -219,4 +226,4 @@ onUnmounted(() => {
height: 60%;
}
}
</style>
</style>

View File

@ -1,3 +1,4 @@
import { to } from 'await-to-js';
import * as echarts from 'echarts/core';
import { text } from 'stream/consumers';
// import { PictorialBarChart } from 'echarts/charts'
@ -255,7 +256,6 @@ export const getLineOption = (lineData: any) => {
const maxData = Math.max(...lineData.line1.flat());
const option = {
backgroundColor: '',
tooltip: {
trigger: 'axis',
@ -313,7 +313,7 @@ export const getLineOption = (lineData: any) => {
axisLabel: {
textStyle: {
color: '#fff'
},
}
}
},
yAxis: {
@ -579,10 +579,10 @@ export const getDishesOption = (data?: any) => {
// 菜品库存图
export const getInventoryOption = () => {
const res = {
data: [2800, 300, 3900, 3000, 2450, 2670, 3320],
name: ['麻辣牛肉', '水煮肉片', '酸菜鱼', '辣子鸡丁', '烧白', '冬瓜排骨汤', '清炒油麦菜'],
ratio: [4000, 4000, 4000, 4000, 4000, 4000, 4000]
},
data: [2800, 300, 3900, 3000, 2450, 2670, 3320],
name: ['麻辣牛肉', '水煮肉片', '酸菜鱼', '辣子鸡丁', '烧白', '冬瓜排骨汤', '清炒油麦菜'],
ratio: [4000, 4000, 4000, 4000, 4000, 4000, 4000]
},
dataIndex = 1;
const option = {
xAxis: {
@ -698,13 +698,13 @@ export const getBarOptions = (data: any) => {
const option = {
backgroundColor: '',
grid: {
left: '8%',
top: '10%', // 顶部留一点空间给 legend
left: '9%',
top: '10%', // 顶部留一点空间给 legend
bottom: '8%',
right: '2%'
},
legend: {
data: ['现金流入', '现金流出'], // 与 series.name 对应
data: ['现金流入', '现金流出'], // 与 series.name 对应
top: '0%',
textStyle: { color: '#fff', fontSize: 12 }
},
@ -716,7 +716,8 @@ export const getBarOptions = (data: any) => {
formatter: (params: any) => {
// params 是数组,对应每条柱子
return params
.map((p: any) => `${p.seriesName}${p.value} 万元`)
.map((p: any) => `${p.seriesName}${Number(p.value).toFixed(2)} 万元`)
.join('<br/>');
},
textStyle: {
@ -758,8 +759,11 @@ export const getBarOptions = (data: any) => {
{
axisLabel: {
formatter: function (value) {
value = value + '万';
return value;
if (value >= 1000) {
return value / 1000 + '千万';
} else {
return value + '万';
}
},
color: 'rgba(255, 255, 255, 0.8)'
},
@ -825,7 +829,9 @@ export const getBarOptions = (data: any) => {
},
label: {
show: false,
formatter: '{c}',
formatter: function (params) {
return Number(params.value).toFixed(2);
},
position: 'top',
color: '#fff',
fontSize: 10
@ -864,11 +870,12 @@ export const getBarOptions = (data: any) => {
},
label: {
show: true,
formatter: '{c}',
formatter: function (params) {
return Number(params.value).toFixed(2);
},
position: 'top',
color: '#fff',
fontSize: 10,
padding: 5
fontSize: 10
}
}
]
@ -898,7 +905,6 @@ export const getBarOptions2 = (data: any) => {
tooltip: {
trigger: 'item',
show: true
},
legend: {
top: '5%',
@ -929,10 +935,10 @@ export const getBarOptions2 = (data: any) => {
{ value: 3, name: '100万以下' },
{ value: 4, name: '100-500万' },
{ value: 5, name: '500-1000万' },
{ value: 4, name: '1000万以上' },
{ value: 4, name: '1000万以上' }
]
}
]
};
return option;
}
};

View File

@ -86,6 +86,7 @@ import { LoginData, TenantVO } from '@/api/types';
import { to } from 'await-to-js';
import { HttpStatus } from '@/enums/RespEnum';
import { useI18n } from 'vue-i18n';
import { getAllRouters } from '@/api/system/menu';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -153,6 +154,7 @@ const handleLogin = () => {
if (!err) {
const redirectUrl = redirect.value || '/';
await router.push(redirectUrl);
loading.value = false;
} else {
loading.value = false;

View File

@ -38,16 +38,11 @@
@click="submitForm"
icon="Check"
class="px-8 py-2.5 transition-all duration-300 transform hover:scale-105 bg-blue-500 hover:bg-blue-600 text-white font-medium"
v-hasPermi="['ailiaoshebei:purchaseUser:byProject']"
v-hasPermi="['cailiaoshebei:purchaseUser:add']"
>
确认提交
</el-button>
<el-button
@click="resetForm"
v-hasPermi="['ailiaoshebei:purchaseUser:byProject']"
icon="Refresh"
class="px-8 py-2.5 transition-all duration-300 border-gray-300 hover:bg-gray-100 font-medium"
>
<el-button @click="resetForm" icon="Refresh" class="px-8 py-2.5 transition-all duration-300 border-gray-300 hover:bg-gray-100 font-medium">
重置
</el-button>
</div>

View File

@ -6,20 +6,44 @@
<el-card shadow="hover">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5" :offset="0"><el-button type="primary"
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:add']" size="default" @click="handleAdd"
icon="FolderAdd" plain>新增</el-button></el-col>
<el-col :span="1.5" :offset="0"><el-button type="danger" size="default"
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:remove']" @click="handleDeleteBatch"
icon="FolderDelete" plain>删除</el-button></el-col>
<el-col :span="1.5" :offset="0">
<el-button
type="primary"
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:add']"
size="default"
@click="handleAdd"
icon="FolderAdd"
plain
>新增</el-button
>
</el-col>
<el-col :span="1.5" :offset="0">
<el-button
type="danger"
size="default"
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:remove']"
@click="handleDeleteBatch"
:disabled="form.mrpBaseBo.status != 'draft'"
icon="FolderDelete"
plain
>删除</el-button
>
</el-col>
</el-row>
</template>
<el-input v-model="batchNumber" placeholder="请输入批次号" @input="searchBatchList" prefix-icon="Search"
clearable />
<el-tree ref="batchTreeRef" class="mt-2" node-key="id" :data="batchOptions"
:props="{ label: 'planCode', children: 'children' }" :expand-on-click-node="false" highlight-current
default-expand-all @node-click="handleNodeClick">
<el-input v-model="batchNumber" placeholder="请输入批次号" @input="searchBatchList" prefix-icon="Search" clearable />
<el-tree
ref="batchTreeRef"
class="mt-2"
node-key="id"
:data="batchOptions"
:props="{ label: 'planCode', children: 'children' }"
:expand-on-click-node="false"
highlight-current
default-expand-all
@node-click="handleNodeClick"
>
<template #default="{ node, data }">
<div class="custom-tree-node">
{{ node.label }}
@ -27,8 +51,14 @@
</div>
</template>
</el-tree>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.batchData.pageNum"
v-model:limit="queryParams.batchData.pageSize" @pagination="getList" layout="prev, pager, next,jumper" />
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.batchData.pageNum"
v-model:limit="queryParams.batchData.pageSize"
@pagination="getList"
layout="prev, pager, next,jumper"
/>
</el-card>
</el-col>
<el-col :span="19">
@ -36,21 +66,21 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5" v-if="form.mrpBaseBo.status == 'draft'">
<el-button type="primary" plain icon="Edit" @click="handleUpdata"
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:edit']">修改</el-button>
<el-button type="primary" plain icon="Edit" @click="handleUpdata" v-hasPermi="['cailiaoshebei:materialbatchdemandplan:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button plain type="warning" icon="Finished" @click="handleAudit()"
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:query']">审核</el-button>
<el-col :span="1.5" v-if="form.mrpBaseBo.status == 'draft'">
<el-button plain type="primary" icon="Finished" @click="handleAudit()">审核</el-button>
</el-col>
<el-col :span="1.5" v-if="form.mrpBaseBo.status != 'draft'">
<el-button type="warning" icon="View" @click="handleAudit()">查看流程</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="cailiaoshebeiList" @selection-change="handleSelectionChange">
<!-- <el-table-column type="selection" width="55" align="center" /> -->
<!-- <el-table-column label="供货商ID" align="center" prop="supplierId" /> -->
<el-table-column label="物资名称" align="center" prop="name" />
<el-table-column label="质量标准" align="center" prop="qs" />
<el-table-column label="规格型号" align="center" prop="specification" />
@ -59,14 +89,19 @@
<el-table-column label="需求到货时间" align="center" prop="arrivalTime" width="250" />
<el-table-column label="备注" align="center" prop="remark" />
</el-table>
<pagination v-show="mainTotal > 0" :total="mainTotal" v-model:page="queryParams.mainData.pageNum"
v-model:limit="queryParams.mainData.pageSize" @pagination="getMainList" />
<pagination
v-show="mainTotal > 0"
:total="mainTotal"
v-model:page="queryParams.mainData.pageNum"
v-model:limit="queryParams.mainData.pageSize"
@pagination="getMainList"
/>
</el-card>
</el-col>
</el-row>
<!-- 添加或修改物资-材料设备对话框 -->
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="1300px" append-to-body>
<el-dialog :close-on-click-modal="false" draggable :title="dialog.title" v-model="dialog.visible" width="1500px" append-to-body>
<el-form :model="form" ref="cailiaoshebeiFormRef" :rules="rules" label-width="80px" :inline="false">
<el-divider>基础信息</el-divider>
<el-row :gutter="20">
@ -77,8 +112,7 @@
</el-col>
<el-col :span="8" :offset="0">
<el-form-item label="编制日期" prop="mrpBaseBo.preparedDate">
<el-date-picker v-model="form.mrpBaseBo.preparedDate" type="date" value-format="YYYY-MM-DD"
placeholder="请选择编制日期" />
<el-date-picker v-model="form.mrpBaseBo.preparedDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择编制日期" />
</el-form-item>
</el-col>
<el-col :span="8" :offset="0">
@ -89,61 +123,93 @@
</el-row>
<el-divider>主要信息</el-divider>
<el-table :data="form.planList">
<el-table-column prop="name" align="center" label="版本号 " width="150">
<!-- 表格添加border属性优化视觉体验 -->
<el-table :data="form.planList" border>
<!-- 版本号列 -->
<el-table-column prop="batchNumber" align="center" label="版本号 " width="200">
<template #default="scope">
<el-select v-model="scope.row.versions" placeholder="请选择"
@change="(val) => selectNameVersion(val, scope.row)">
<el-option v-for="item in versionList" :key="item.versions" :label="item.versions"
:value="item.versions" />
<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-select>
</template>
</el-table-column>
<el-table-column prop="name" align="center" label="物资名称">
<!-- 物资名称列 -->
<el-table-column prop="name" align="center" label="物资名称" width="160">
<template #default="scope">
<el-select :disabled="!scope.row.versions" v-model="scope.row.suppliespriceId" placeholder="请选择"
@change="(val) => selectName(val, scope.row)">
<el-input v-model="scope.row.name" v-if="scope.row.mrpBaseId" placeholder="请输入物资名称" disabled />
<el-select
v-else
:disabled="!scope.row.batchNumber"
v-model="scope.row.suppliespriceId"
placeholder="请选择"
@change="(val) => selectName(val, scope.row, scope.$index)"
>
<el-option v-for="item in nameList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</template>
</el-table-column>
<el-table-column prop="specification" align="center" label="规格型号" width="150">
<!-- 剩余量列 -->
<el-table-column align="center" label="剩余量" width="80">
<template #default="scope">
<el-input v-model="scope.row.specification" placeholder="请输入规格型号" disabled />
<span>{{ scope.row.Remaining }}</span>
<!-- <el-input disabled v-model="scope.row.Remaining" placeholder="剩余量" /> -->
</template>
</el-table-column>
<el-table-column prop="unit" align="center" label="单位" width="130">
<!-- 规格型号列 -->
<el-table-column prop="specification" align="center" label="规格型号" width="100">
<template #default="scope">
<el-input v-model="scope.row.unit" placeholder="请输入单位" disabled />
<span>{{ scope.row.specification }}</span>
<!-- <el-input v-model="scope.row.specification" placeholder="请输入规格型号" disabled /> -->
</template>
</el-table-column>
<el-table-column prop="demandQuantity" align="center" label="数量" width="130">
<!-- 单位列 -->
<el-table-column prop="unit" align="center" label="单位" width="80">
<template #default="scope">
<el-input v-model="scope.row.demandQuantity" placeholder="请输入数量" type="number" min="0" disabled />
<span>{{ scope.row.unit }}</span>
<!-- <el-input v-model="scope.row.unit" placeholder="请输入单位" disabled /> -->
</template>
</el-table-column>
<el-table-column prop="qs" align="center" label="质量标准" width="150">
<!-- 数量列新增错误提示展示 -->
<el-table-column prop="demandQuantity" align="center" label="数量" width="140">
<template #default="scope">
<el-input
v-model.number="scope.row.demandQuantity"
@input="validateDemandQuantity(scope.row, scope.$index)"
@blur="validateDemandQuantity(scope.row, scope.$index)"
:max="scope.row.Remaining"
placeholder="请输入数量"
type="number"
min="0"
/>
<!-- 数量错误提示红色小字体 -->
<div v-if="scope.row.quantityError" class="text-red-500 text-xs mt-1">{{ scope.row.quantityError }}</div>
</template>
</el-table-column>
<!-- 质量标准列 -->
<el-table-column prop="qs" align="center" label="质量标准" width="140">
<template #header> <span class="text-red-500">*</span> 质量标准 </template>
<template #default="scope">
<el-input v-model="scope.row.qs" placeholder="请输入质量标准" />
</template>
</el-table-column>
<el-table-column prop="arrivalTime" align="center" label="需求到货时间">
<!-- 需求到货时间列 -->
<el-table-column prop="arrivalTime" align="center" label="需求到货时间" width="180">
<template #header> <span class="text-red-500">*</span> 需求到货时间 </template>
<template #default="scope">
<el-date-picker v-model="scope.row.arrivalTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择"
style="width: 140px" />
<el-date-picker v-model="scope.row.arrivalTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择" style="width: 140px" />
</template>
</el-table-column>
<el-table-column prop="remark" align="center" label="备注" width="150">
<!-- 备注 -->
<el-table-column prop="remark" align="center" label="备注">
<template #default="scope">
<el-input v-model="scope.row.remark" placeholder="请输入备注" disabled />
</template>
</el-table-column>
<!-- 操作列 -->
<el-table-column prop="remark" align="center" label="操作" width="150">
<template #default="scope">
<el-button @click="addRow" type="success" icon="Plus" circle size="small" />
<el-button @click="delRow(scope.$index)" type="danger" icon="Delete" circle size="small" />
<el-button @click="addRow" type="primary" icon="Plus" size="small" />
<el-button @click="delRow(scope.$index)" type="danger" icon="Delete" size="small" />
</template>
</el-table-column>
</el-table>
@ -165,11 +231,51 @@ import {
listBatch,
getBatch,
delBatch,
listSelectCailiaoshebei, obtainTheVersion,
getDictList, coryEngineeringList
listSelectCailiaoshebei,
obtainTheVersion,
getDictList,
coryEngineeringList,
mrpBaseRemaining
} from '@/api/materials/batchPlan';
import { CailiaoshebeiVO, CailiaoshebeiQuery, CailiaoshebeiForm } from '@/api/materials/batchPlan/types';
import { useUserStoreHook } from '@/store/modules/user';
import { getCurrentInstance, ComponentInternalInstance, watch, onMounted, onUnmounted } from 'vue';
import type { ElFormInstance } from 'element-plus';
// 类型定义补充
interface DialogOption {
visible: boolean;
title: string;
}
interface PlanListItem {
id?: number | undefined;
name?: string | undefined;
specification?: string | undefined;
unit?: string | undefined;
suppliespriceId?: number | undefined;
demandQuantity?: number | undefined;
qs?: string | undefined;
arrivalTime?: string | undefined;
remark?: string | undefined;
Remaining: number; // 剩余量(必存在)
quantityError: string; // 数量错误提示
batchNumber?: string | undefined; // 版本号
duplicateError: string; // 重复错误提示
mrpBaseId?: number | undefined;
}
interface FormData {
mrpBaseBo: {
id?: number | undefined;
preparedDate?: string | undefined;
planCode?: string | undefined;
matCat?: string | undefined;
status?: string | undefined;
projectId?: number | undefined;
};
planList: PlanListItem[];
}
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 获取用户 store
@ -187,17 +293,17 @@ const multiple = ref(true);
const total = ref(0);
const mainTotal = ref(0);
const batchOptions = ref<any[]>([]);
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status') || {});
const route = useRoute();
const queryFormRef = ref<ElFormInstance>();
const cailiaoshebeiFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: any = {
// 初始化表单数据(补充版本号、重复错误提示字段)
const initFormData: FormData = {
mrpBaseBo: {
id: undefined,
preparedDate: undefined,
@ -206,7 +312,6 @@ const initFormData: any = {
status: undefined,
projectId: currentProject.value?.id
},
planList: [
{
id: undefined,
@ -217,18 +322,23 @@ const initFormData: any = {
demandQuantity: undefined,
qs: undefined,
arrivalTime: undefined,
remark: undefined
remark: undefined,
Remaining: 0, // 初始化剩余量
quantityError: '', // 初始化数量错误提示
batchNumber: undefined, // 初始化版本号
duplicateError: '', // 初始化重复错误提示
mrpBaseId: undefined
}
]
};
const data = reactive({
form: { ...initFormData },
form: { ...initFormData } as FormData,
queryParams: {
batchData: {
pageNum: 1,
pageSize: 10,
planCode: undefined,
projectId: currentProject.value?.id
},
mainData: {
@ -245,77 +355,187 @@ const data = reactive({
'mrpBaseBo.matCat': [{ required: true, message: '物资分类不能为空', trigger: 'blur' }]
}
});
const batchNumber = ref('');
const { queryParams, form, rules } = toRefs(data);
const nameList = ref([]);
const versionList = ref([]);
const nameList = ref<any[]>([]);
const versionList = ref<any[]>([]);
/** 查询物资-材料设备列表 */
const getList = async (type?: string) => {
loading.value = true;
const res = await listBatch(queryParams.value.batchData);
batchOptions.value = res.rows;
if (res.rows && res.rows.length > 0 && !queryParams.value.mainData.mrpBaseId) {
batchTreeRef.value.setCurrentKey(res.rows[0].id);
queryParams.value.mainData.mrpBaseId = res.rows[0].id;
form.value.mrpBaseBo.status = res.rows[0].status;
try {
const res = await listBatch(queryParams.value.batchData);
batchOptions.value = res.rows || [];
// 自动选中第一条数据(如果存在且未选中)
if (batchOptions.value.length > 0 && !queryParams.value.mainData.mrpBaseId) {
batchTreeRef.value?.setCurrentKey(batchOptions.value[0].id);
queryParams.value.mainData.mrpBaseId = batchOptions.value[0].id;
form.value.mrpBaseBo.status = batchOptions.value[0].status;
}
total.value = res.total || 0;
} catch (error) {
proxy?.$modal.msgError('获取批次列表失败');
} finally {
loading.value = false;
// 非搜索场景下同步加载主列表
if (type !== 'search') {
getMainList();
}
}
total.value = res.total;
loading.value = false;
if (type === 'search') return;
getMainList();
};
const selectName = (val: any, row: any) => {
const selected = nameList.value.find((item) => item.id === val);
if (selected) {
row.name = selected.name;
row.specification = selected.specification;
row.unit = selected.unit;
row.qs = selected.qs;
row.demandQuantity = selected.quantity;
row.remark = selected.remark;
row.arrivalTime = selected.arrivalTime;
/** 数量校验:必须≤剩余量,且为合法数字 */
const validateDemandQuantity = (row: PlanListItem, index: number) => {
// 1. 清除之前的错误信息
row.quantityError = '';
// 2. 处理空值若需必填可补充row.quantityError = '数量不能为空'
if (row.demandQuantity === null || row.demandQuantity === undefined || row.demandQuantity === '') {
return;
}
// 3. 处理非数字
if (typeof row.demandQuantity !== 'number' || isNaN(row.demandQuantity)) {
row.quantityError = '请输入合法数字';
return;
}
// 4. 处理负数
if (row.demandQuantity < 0) {
row.quantityError = '数量不能为负数';
return;
}
// 5. 核心校验:数量≤剩余量
if (row.demandQuantity > row.Remaining) {
row.quantityError = `数量不能超过剩余量${row.Remaining}`;
}
};
/** 获取剩余量 */
const getMrpBaseRemaining = async (suppliespriceId: number, row: PlanListItem) => {
try {
const res = await mrpBaseRemaining({ suppliespriceId });
row.Remaining = res.data || 0;
// 剩余量更新后,重新校验当前数量
validateDemandQuantity(row, 0);
} catch (error) {
proxy?.$modal.msgError('获取剩余量失败');
row.Remaining = 0;
}
};
/** 校验重复数据:版本号+物资名称不能重复 */
const checkDuplicate = () => {
const planList = form.value.planList;
let hasDuplicate = false;
// 1. 清除所有重复错误提示
planList.forEach((item) => {
item.duplicateError = '';
});
// 2. 遍历校验重复(只校验版本号和物资名称都存在的行)
for (let i = 0; i < planList.length; i++) {
const current = planList[i];
// 跳过版本号或物资名称为空的行
if (!current.batchNumber || !current.suppliespriceId) continue;
for (let j = i + 1; j < planList.length; j++) {
const compare = planList[j];
if (!compare.batchNumber || !compare.suppliespriceId) continue;
// 版本号和物资ID都相同则判定为重复
if (current.batchNumber === compare.batchNumber && current.suppliespriceId === compare.suppliespriceId) {
current.duplicateError = `与第${j + 1}行重复(同版本+同物资)`;
compare.duplicateError = `与第${i + 1}行重复(同版本+同物资)`;
hasDuplicate = true;
}
}
}
return hasDuplicate;
};
/** 选择物资名称触发(新增索引参数,用于触发重复校验) */
const selectName = (val: number, row: PlanListItem, index: number) => {
console.log(row);
// 1. 获取剩余量并更新基础信息
getMrpBaseRemaining(val, row).then(() => {
const selected = nameList.value.find((item: any) => item.id === val);
if (selected) {
row.name = selected.name;
row.specification = selected.specification;
row.unit = selected.unit;
row.qs = selected.qs || '';
row.remark = selected.remark || '';
row.arrivalTime = selected.arrivalTime || '';
}
// 2. 触发重复校验
checkDuplicate();
});
};
/** 节点单击事件 */
const handleNodeClick = (data: any) => {
queryParams.value.mainData.mrpBaseId = data.id;
form.value.mrpBaseBo.status = data.status;
getMainList();
};
/** 获取主列表数据 */
const getMainList = async () => {
if (!queryParams.value.mainData.mrpBaseId) return;
const res = await getBatch(queryParams.value.mainData);
cailiaoshebeiList.value = res.rows;
mainTotal.value = res.total;
loading.value = true;
try {
const res = await getBatch(queryParams.value.mainData);
cailiaoshebeiList.value = res.rows || [];
mainTotal.value = res.total || 0;
} catch (error) {
proxy?.$modal.msgError('获取物资列表失败');
} finally {
loading.value = false;
}
};
/** 搜索批次列表 */
const searchBatchList = async () => {
queryParams.value.batchData.planCode = batchNumber.value;
getList('search');
};
//删除
/** 删除表格行 */
const delRow = (index: number) => {
if (form.value.planList.length <= 1) return proxy?.$modal.msgWarning('请至少保留一项');
if (form.value.planList.length <= 1) {
return proxy?.$modal.msgWarning('请至少保留一项物资数据');
}
form.value.planList.splice(index, 1);
// 删除后重新校验重复(避免删除重复行后错误提示残留)
checkDuplicate();
};
//新增
/** 新增表格行 */
const addRow = () => {
form.value.planList.push({
const newRow: PlanListItem = {
name: undefined,
specification: undefined,
unit: undefined,
suppliespriceId: undefined,
demandQuantity: undefined,
qs: undefined,
arrivalTime: undefined,
remark: undefined
});
remark: undefined,
Remaining: 0,
quantityError: '',
batchNumber: undefined,
duplicateError: '',
mrpBaseId: undefined
};
form.value.planList.push(newRow);
};
/** 取消按钮 */
@ -327,41 +547,22 @@ const cancel = () => {
/** 表单重置 */
const reset = () => {
const status = form.value.mrpBaseBo.status;
form.value = { ...initFormData, status }; // 重置但保留
// 重置表单(保留状态字段)
form.value = {
...JSON.parse(JSON.stringify(initFormData)),
mrpBaseBo: { ...initFormData.mrpBaseBo, status }
};
// 重置表单验证状态
cailiaoshebeiFormRef.value?.resetFields();
// 重置项目ID
form.value.mrpBaseBo.projectId = currentProject.value?.id;
form.value.planList = [
{
name: undefined,
specification: undefined,
unit: undefined,
suppliespriceId: undefined,
demandQuantity: undefined,
qs: undefined,
arrivalTime: undefined,
remark: undefined
}
];
};
// /** 搜索按钮操作 */
// const handleQuery = () => {
// queryParams.value.pageNum = 1;
// getList();
// };
// /** 重置按钮操作 */
// const resetQuery = () => {
// queryFormRef.value?.resetFields();
// handleQuery();
// };
/** 多选框选中数据 */
const handleSelectionChange = (selection: CailiaoshebeiVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
single.value = selection.length !== 1;
multiple.value = selection.length === 0;
};
/** 新增按钮操作 */
@ -371,130 +572,255 @@ const handleAdd = () => {
dialog.title = '新增物资-需求';
};
/** 修改按钮操作 */
const handleUpdata = () => {
if (!queryParams.value.mainData.mrpBaseId) {
return proxy?.$modal.msgError('请先选择批次');
}
// 1. 获取对应版本的物资列表
reset();
getCailiaoshebei(queryParams.value.mainData.mrpBaseId).then((res: any) => {
form.value.mrpBaseBo = res.data.mrpBaseBo;
const allowedKeys = Object.keys(initFormData.planList[0]);
form.value.planList = res.data.planList.map((item) => {
return allowedKeys.reduce((obj, key) => {
obj[key] = item[key] ?? undefined;
return obj;
}, {});
});
loading.value = true;
getCailiaoshebei(queryParams.value.mainData.mrpBaseId)
.then((res: any) => {
// 1. 更新基础信息
form.value.mrpBaseBo = res.data.mrpBaseBo || initFormData.mrpBaseBo;
console.log(form.value.planList);
});
dialog.visible = true;
dialog.title = '修改物资-需求';
// 2. 更新表格数据(补充缺失字段)
form.value.planList = (res.data.planList || []).map((item: any) => ({
id: item.id,
name: item.name,
specification: item.specification,
unit: item.unit,
suppliespriceId: item.suppliespriceId,
demandQuantity: item.demandQuantity,
qs: item.qs,
arrivalTime: item.arrivalTime,
remark: item.remark,
Remaining: Number(item.remaining) || 0,
// remaining:
quantityError: '',
batchNumber: item.batchNumber,
duplicateError: '',
mrpBaseId: item.mrpBaseId
}));
// 3. 打开对话框
dialog.visible = true;
dialog.title = '修改物资-需求';
})
.catch(() => {
proxy?.$modal.msgError('获取详情失败');
})
.finally(() => {
loading.value = false;
});
};
/** 提交数据 */
/** 提交数据(整合所有校验) */
const submitTransferForm = async () => {
const result = validateAndClean(form.value.planList);
console.log('🚀 ~ submitTransferForm ~ form.value.planList:', form.value.planList);
if (!result.valid) {
proxy?.$modal.msgError('验证失败,主要信息存在部分字段缺失的数据项');
return;
// 1. 先校验重复数据
const hasDuplicate = checkDuplicate();
if (hasDuplicate) {
return proxy?.$modal.msgError('存在重复的版本号+物资组合,请修正后提交');
}
// 2. 校验数量合法性(检查是否有数量错误)
const hasQuantityError = form.value.planList.some((row) => row.quantityError);
if (hasQuantityError) {
return proxy?.$modal.msgError('存在非法数量,请修正后提交');
}
// 3. 执行表单基础验证
const result = validateAndClean(form.value.planList);
if (!result.valid) {
return proxy?.$modal.msgError(result.message);
}
// 4. 表单组件验证
cailiaoshebeiFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
form.value.planList = result.data;
await updateCailiaoshebei(form.value).finally(() => (buttonLoading.value = false));
if (!valid) return;
buttonLoading.value = true;
try {
// 5. 提交数据
await updateCailiaoshebei({
...form.value,
planList: result.data // 使用清洗后的数据
});
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
// 6. 刷新列表
await getList();
} catch (error) {
proxy?.$modal.msgError('操作失败,请重试');
} finally {
buttonLoading.value = false;
}
});
};
/** 删除批次 */
const handleDeleteBatch = async () => {
const _ids = batchTreeRef.value.getCurrentNode()?.id;
await proxy?.$modal.confirm('是否确认删除批次编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delBatch(_ids);
proxy?.$modal.msgSuccess('删除成功');
queryParams.value.mainData.mrpBaseId = undefined;
await getList();
const _id = batchTreeRef.value?.getCurrentNode()?.id;
if (!_id) {
return proxy?.$modal.msgError('请先选择批次');
}
try {
await proxy?.$modal.confirm('是否确认删除该批次?删除后不可恢复!');
await delBatch(_id);
proxy?.$modal.msgSuccess('删除成功');
// 重置选中状态并刷新列表
queryParams.value.mainData.mrpBaseId = undefined;
form.value.mrpBaseBo.status = undefined;
await getList();
} catch (error) {
// 取消确认时不提示错误
if (error !== 'cancel') {
proxy?.$modal.msgError('删除失败');
}
}
};
//检测主要信息填写状况
function validateAndClean(arr) {
// 过滤掉全空的数据项
const cleanedArr = arr.filter((item) => !Object.values(item).every((v) => v === '' || v == null));
let hasFullItem = false; // 是否有一条全填数据
/** 数据清洗与基础校验 */
function validateAndClean(arr: PlanListItem[]) {
// 1. 过滤掉全空的数据项
const cleanedArr = arr.filter((item) => !Object.values(item).every((v) => v === '' || v == null || v === undefined));
for (const item of cleanedArr) {
const keys = Object.keys(item).filter((k) => k !== 'remark' && k !== 'id');
const allFilled = keys.every((k) => item[k] !== '' && item[k] != null);
if (allFilled) {
hasFullItem = true; // 有一条全填
let hasFullItem = false; // 是否有至少一条完整数据
// 2. 逐行校验必填项
for (let idx = 0; idx < cleanedArr.length; idx++) {
const item = cleanedArr[idx];
// 校验版本号
if (!item.batchNumber) {
return { valid: false, message: `${idx + 1}行:版本号不能为空`, data: cleanedArr };
}
const allEmpty = Object.values(item).every((v) => v === '' || v == null);
// 如果不是全填,也不是全空(部分填) → 直接返回失败
if (!allFilled && !allEmpty) {
return { valid: false, data: cleanedArr };
// 校验物资选择
if (!item.suppliespriceId) {
return { valid: false, message: `${idx + 1}行:请选择物资名称`, data: cleanedArr };
}
// 校验质量标准
if (!item.qs) {
return { valid: false, message: `${idx + 1}行:质量标准不能为空`, data: cleanedArr };
}
// 校验需求到货时间
if (!item.arrivalTime) {
return { valid: false, message: `${idx + 1}行:需求到货时间不能为空`, data: cleanedArr };
}
// 校验数量必填且≥0
if (item.demandQuantity === null || item.demandQuantity === undefined || item.demandQuantity < 0) {
return { valid: false, message: `${idx + 1}行:请输入合法的需求数量`, data: cleanedArr };
}
hasFullItem = true;
}
// 如果没有至少一条全填,返回失败
// 3. 检查是否至少有一条完整数据
if (!hasFullItem) {
return { valid: false, data: cleanedArr };
return { valid: false, message: '至少需要填写一条完整的物资数据', data: cleanedArr };
}
return { valid: true, data: cleanedArr };
return { valid: true, message: '', data: cleanedArr };
}
/** 审核按钮操作 */
const handleAudit = async () => {
if (!form.value.mrpBaseBo.status) {
proxy?.$modal.msgError('请选择批次号');
return;
return proxy?.$modal.msgError('请选择批次号');
}
if (!queryParams.value.mainData.mrpBaseId) {
return proxy?.$modal.msgError('请选择批次号');
}
// 关闭当前页并打开审核页
proxy?.$tab.closePage(route);
proxy?.$tab.openPage('/approval/batchPlan/indexEdit', '审核物资设备批次需求计划', {
id: queryParams.value.mainData.mrpBaseId,
status: form.value.mrpBaseBo.status + '_batchRequirements',
status: `${form.value.mrpBaseBo.status}_batchRequirements`,
type: 'update'
});
};
const getNameList = (versions) => {
coryEngineeringList({ projectId: currentProject.value?.id, versions }).then((res) => {
nameList.value = res.data;
});
};
// 获取版本号
const getVersion = () => {
obtainTheVersion({ projectId: currentProject.value?.id }).then((res) => {
versionList.value = res.data;
});
};
const selectNameVersion = (val, row) => {
row.suppliespriceId = undefined;
getNameList(val);
/** 获取物资列表(按版本号筛选) */
const getNameList = (versions: string) => {
coryEngineeringList({
projectId: currentProject.value?.id,
versions
})
.then((res: any) => {
nameList.value = res.data || [];
})
.catch(() => {
nameList.value = [];
proxy?.$modal.msgError('获取物资列表失败');
});
};
/** 获取版本号列表 */
const getVersion = () => {
obtainTheVersion({ projectId: currentProject.value?.id })
.then((res: any) => {
versionList.value = res.data || [];
})
.catch(() => {
versionList.value = [];
proxy?.$modal.msgError('获取版本号失败');
});
};
/** 选择版本号触发(新增索引参数,用于触发重复校验) */
const selectNameVersion = (val: string, row: PlanListItem, index: number) => {
row.batchNumber = val;
row.suppliespriceId = undefined; // 切换版本号时清空物资选择
row.name = undefined;
row.specification = undefined;
row.unit = undefined;
row.qs = undefined;
row.remark = undefined;
row.arrivalTime = undefined;
row.demandQuantity = undefined;
row.quantityError = '';
row.duplicateError = '';
row.mrpBaseId = '';
// 1. 获取对应版本的物资列表
getNameList(val);
// 2. 触发重复校验(清空物资后可能消除重复)
checkDuplicate();
};
/** 页面挂载时初始化 */
onMounted(() => {
getList();
// getNameList();
getVersion();
});
//监听项目id刷新数据
/** 监听项目ID变化刷新数据 */
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
queryParams.value.mainData.projectId = nid;
queryParams.value.batchData.projectId = nid;
form.value.mrpBaseBo.projectId = nid;
getList();
(newId, oldId) => {
if (newId !== oldId && newId) {
queryParams.value.mainData.projectId = newId;
queryParams.value.batchData.projectId = newId;
form.value.mrpBaseBo.projectId = newId;
getList();
getVersion(); // 重新获取对应项目的版本号
}
}
);
/** 页面卸载时清理监听 */
onUnmounted(() => {
listeningProject();
});
</script>
<style scoped lang="scss">
.custom-tree-node {
flex: 1;
@ -504,4 +830,17 @@ onUnmounted(() => {
font-size: 14px;
padding-right: 8px;
}
/* 错误提示样式补充 */
.text-red-500 {
color: #f56c6c;
}
.text-xs {
font-size: 12px;
}
.dialog-footer {
text-align: right;
}
</style>

View File

@ -26,8 +26,8 @@
<el-input v-model="queryParams.storageUnit" placeholder="请输入保管单位" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" v-hasPermi="['materials:materialIssue:list']" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" v-hasPermi="['materials:materialIssue:list']" @click="resetQuery">重置</el-button>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
@ -39,16 +39,11 @@
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['materials:materialIssue:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['materials:materialIssue:remove']"
>删除</el-button
>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="materialIssueList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" width="60" label="序号" align="center" />
<el-table-column label="表单编号" align="center" prop="formCode" />
<el-table-column label="工程名称" align="center" prop="projectName" />
<el-table-column label="设备材料名称" align="center" prop="materialName" />
@ -58,23 +53,13 @@
<el-table-column label="保管单位" align="center" prop="storageUnit" />
<el-table-column label="缺陷情况" align="center" prop="defectDescription" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<el-table-column label="操作" align="center" min-width="150" fixed="right">
<template #default="scope">
<el-tooltip content="查看" placement="top">
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['materials:materialIssue:query']"></el-button>
</el-tooltip>
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialIssue:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
link
type="primary"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['materials:materialIssue:remove']"
></el-button>
</el-tooltip>
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['materials:materialIssue:query']">查看</el-button>
<!-- <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialIssue:edit']">修改</el-button> -->
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materialIssue:remove']"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
@ -100,9 +85,10 @@
<el-input v-model="form.projectName" placeholder="请输入工程名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-col :span="24">
<!-- 设备材料名称从数量验收列表自动生成禁用手动输入 -->
<el-form-item label="设备材料名称" prop="materialName">
<el-input v-model="form.materialName" placeholder="请输入设备材料名称" />
<el-input v-model="form.materialName" placeholder="由数量验收列表中的名称自动生成" disabled style="cursor: not-allowed" />
</el-form-item>
</el-col>
<el-col :span="12">
@ -144,8 +130,8 @@
:prop="`itemList.${index}.name`"
:rules="[{ required: true, message: '名称不能为空', trigger: 'blur' }]"
>
<el-select v-model="item.name" placeholder="请输入名称" @change="(value) => getNameChange(value, index, item)">
<el-option v-for="item in optionsName" :key="item.id" :label="item.materialsName" :value="item.id" />
<el-select v-model="item.inventoryId" placeholder="请选择名称" @change="(value) => getNameChange(value, index, item)">
<el-option v-for="opt in optionsName" :key="opt.id" :label="opt.materialsName" :value="opt.id" />
</el-select>
</el-form-item>
</el-col>
@ -155,7 +141,7 @@
:prop="`itemList.${index}.specification`"
:rules="[{ required: true, message: '规格不能为空', trigger: 'blur' }]"
>
<el-input v-model="item.specification" placeholder="请输入规格" />
<el-input disabled v-model="item.specification" placeholder="请输入规格" />
</el-form-item>
</el-col>
<el-col :span="12">
@ -164,41 +150,51 @@
:prop="`itemList.${index}.unit`"
:rules="[{ required: true, message: '单位不能为空', trigger: 'blur' }]"
>
<el-input v-model="item.unit" placeholder="请输入单位" />
<el-input disabled v-model="item.unit" placeholder="请输入单位" />
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item
label="库存"
:prop="`itemList.${index}.stockQuantity`"
:rules="[{ required: true, message: '库存不能为空', trigger: 'blur' }]"
:rules="[
{ required: true, message: '库存不能为空', trigger: 'blur' },
{ type: 'number', min: 0, message: '库存不能小于0', trigger: ['blur', 'change'] }
]"
>
<el-input v-model="item.stockQuantity" placeholder="请输入库存" />
<el-input
v-model.number="item.stockQuantity"
placeholder="请输入库存"
@input="handleStockChange(index)"
@blur="handleStockChange(index)"
/>
</el-form-item>
</el-col> -->
<el-col :span="12">
<el-form-item label="领取" :prop="`itemList.${index}.issuedQuantity`">
<el-input
v-model.number="item.issuedQuantity"
disabled
placeholder="请输入领取数量"
@input="handleIssuedChange(index)"
@blur="handleIssuedChange(index)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="领取"
:prop="`itemList.${index}.issuedQuantity`"
:rules="[{ required: true, message: '领取数量不能为空', trigger: 'blur' }]"
>
<el-input v-model="item.issuedQuantity" placeholder="请输入领取数量" />
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item
label="剩余"
:prop="`itemList.${index}.remainingQuantity`"
:rules="[{ required: true, message: '剩余数量不能为空', trigger: 'blur' }]"
>
<el-input v-model="item.remainingQuantity" placeholder="请输入剩余数量" />
<el-input v-model.number="item.remainingQuantity" placeholder="请输入剩余数量" readonly />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-form-item label="备注" :prop="`itemList.${index}.remark`">
<el-input v-model="item.remark" placeholder="请输入内容" />
</el-form-item>
</el-col>
</el-col> -->
<el-col :span="12" v-if="form.itemList.length > 1">
<div class="item-actions">
<el-button type="danger" link @click="removeItem(index)" icon="Delete">删除</el-button>
@ -257,12 +253,16 @@ import {
delMaterialIssue,
addMaterialIssue,
updateMaterialIssue,
inventoryList,
getMaterialName
} from '@/api/materials/materialIssue';
import { MaterialIssueVO, MaterialIssueQuery, MaterialIssueForm } from '@/api/materials/materialIssue/types';
import { useUserStoreHook } from '@/store/modules/user';
import wordllssue from './word/index.vue';
import { watch, onMounted, onUnmounted, ref, reactive, computed, getCurrentInstance } from 'vue';
import type { ComponentInternalInstance, ElFormInstance, DialogOption } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 获取用户 store
const userStore = useUserStoreHook();
@ -280,6 +280,8 @@ const total = ref(0);
const wordllssueRef = ref<InstanceType<typeof wordllssue>>();
const queryFormRef = ref<ElFormInstance>();
const materialIssueFormRef = ref<ElFormInstance>();
// 存储每个条目的watch停止函数
const itemWatchStopFns = ref<Array<() => void>>([]);
const dialog = reactive<DialogOption>({
visible: false,
@ -294,7 +296,7 @@ const getInitFormData = () => {
materialSource: '1',
formCode: undefined,
projectName: undefined,
materialName: undefined,
materialName: '', // 初始化为空字符串
orderingUnit: undefined,
supplierUnit: undefined,
issueUnit: undefined,
@ -317,13 +319,15 @@ const getInitFormData = () => {
stockQuantity: undefined,
issuedQuantity: undefined,
remainingQuantity: undefined,
name: undefined,
remark: undefined
name: undefined, // 数量验收的名称
remark: undefined,
materialsId: undefined
}
]
};
};
const data = reactive<PageData<MaterialIssueForm, MaterialIssueQuery>>({
const data = reactive({
form: getInitFormData(),
queryParams: {
pageNum: 1,
@ -341,43 +345,127 @@ const data = reactive<PageData<MaterialIssueForm, MaterialIssueQuery>>({
params: {}
},
rules: {
id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }]
formCode: [{ required: true, message: '请输入表单编号', trigger: 'blur' }],
projectName: [{ required: true, message: '请输入工程名称', trigger: 'blur' }],
materialName: [{ required: true, message: '请先在数量验收列表中选择名称', trigger: 'blur' }], // 确保有名称生成
orderingUnit: [{ required: true, message: '请输入订货单位', trigger: 'blur' }],
supplierUnit: [{ required: true, message: '请输入供货单位', trigger: 'blur' }],
issueUnit: [{ required: true, message: '请输入领料单位', trigger: 'blur' }],
storageUnit: [{ required: true, message: '请输入保管单位', trigger: 'blur' }]
}
});
const { queryParams, form, rules } = toRefs(data);
const optionsName: any = ref([]);
/**
* 核心函数:从数量验收列表提取名称,用逗号拼接生成设备材料名称
*/
const computeMaterialName = () => {
if (!form.value.itemList || form.value.itemList.length === 0) {
form.value.materialName = '';
return;
}
// 过滤空名称,去重(可选,根据业务需求决定是否去重)
const validNames = form.value.itemList
.filter((item) => item.name && item.name.trim() !== '')
.map((item) => item.name.trim())
.filter((name, index, self) => self.indexOf(name) === index); // 去重(如需保留重复则删除这行)
form.value.materialName = validNames.join(',');
};
/** 查询物料领料单列表 */
const getList = async () => {
loading.value = true;
const res = await listMaterialIssue(queryParams.value);
materialIssueList.value = res.rows;
total.value = res.total;
loading.value = false;
};
const optionsName: any = ref([]);
//获取一起名称
const getName = async () => {
const res = await getMaterialName(currentProject.value.id);
console.log(res);
if (res.code == 200) {
optionsName.value = res.data;
try {
const res = await listMaterialIssue(queryParams.value);
materialIssueList.value = res.rows;
total.value = res.total;
} finally {
loading.value = false;
}
};
// 获取材料名称列表
const getName = async () => {
try {
const res = await inventoryList(currentProject.value.id);
console.log(res);
if (res.code == 200) {
optionsName.value = res.data;
}
} catch (error) {
proxy?.$modal.msgError('获取材料名称失败');
}
};
// 材料名称选择变化处理修改select的value为名称而非ID
const getNameChange = (value, index, item) => {
// 这里可以添加处理逻辑
console.log(value);
const selected = optionsName.value.find((opt) => opt.id === value);
if (selected) {
item.name = selected.materialsName; // 直接赋值名称
item.materialsId = selected.id; // 保留ID用于后端
item.specification = selected.typeSpecificationName;
item.unit = selected.weightId;
item.issuedQuantity = selected.number;
item.stockQuantity = Number(selected.inventoryNumber) || 0;
// calculateRemaining(index); // 计算剩余数量
}
};
const data = optionsName.value.find((item) => item.id == value);
console.log(data);
/** 验证领取数量不能超过库存 */
const validateIssuedQuantity = (rule, value, callback, index) => {
const item = form.value.itemList[index];
const stock = Number(item.stockQuantity) || 0;
const issued = Number(value) || 0;
form.value.itemList[index].name = data.materialsName;
form.value.itemList[index].materialsId = data.id;
form.value.itemList[index].specification = data.typeSpecificationName;
form.value.itemList[index].unit = data.weightId;
form.value.itemList[index].stockQuantity = data.inventoryNumber;
if (stock === 0) {
callback();
return;
}
if (issued > stock) {
callback(new Error(`领取数量不能超过库存(${stock})`));
} else {
callback();
}
};
/** 计算剩余数量(库存 - 领取数量) */
const calculateRemaining = (index: number) => {
const item = form.value.itemList[index];
const stock = Number(item.stockQuantity) || 0;
const issued = Number(item.issuedQuantity) || 0;
// 确保领取数量不超过库存
if (issued > stock) {
item.issuedQuantity = stock;
proxy?.$modal.msgWarning(`领取数量不能超过库存(${stock}),已自动调整`);
}
// 计算剩余数量
item.remainingQuantity = stock - (item.issuedQuantity || 0);
};
/** 库存变化时重新计算剩余数量 */
const handleStockChange = (index: number) => {
calculateRemaining(index);
// 触发验证
if (materialIssueFormRef.value) {
materialIssueFormRef.value.validateField(`itemList.${index}.issuedQuantity`);
materialIssueFormRef.value.validateField(`itemList.${index}.remainingQuantity`);
}
};
/** 领取数量变化时重新计算剩余数量 */
const handleIssuedChange = (index: number) => {
calculateRemaining(index);
// 触发验证
if (materialIssueFormRef.value) {
materialIssueFormRef.value.validateField(`itemList.${index}.remainingQuantity`);
}
};
/** 取消按钮 */
@ -388,8 +476,38 @@ const cancel = () => {
/** 表单重置 */
const reset = () => {
// 停止所有监听
itemWatchStopFns.value.forEach((stop) => stop());
itemWatchStopFns.value = [];
form.value = getInitFormData();
materialIssueFormRef.value?.resetFields();
// 重新监听初始条目
if (form.value.itemList.length > 0) {
watchItemChanges(0);
}
// 初始计算一次材料名称
computeMaterialName();
};
/** 监听条目变化,自动计算剩余数量 */
const watchItemChanges = (index: number) => {
// 停止已有监听
if (itemWatchStopFns.value[index]) {
itemWatchStopFns.value[index]();
}
// // 监听库存和领取数量变化
// const stop = watch(
// () => [form.value.itemList[index].stockQuantity, form.value.itemList[index].issuedQuantity],
// () => {
// calculateRemaining(index);
// },
// { immediate: true }
// );
itemWatchStopFns.value[index] = stop;
};
/** 搜索按钮操作 */
@ -416,16 +534,58 @@ const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = '添加物料领料单';
// 新增时初始计算材料名称
computeMaterialName();
};
/** 修改按钮操作 */
const handleUpdate = async (row?: MaterialIssueVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await getMaterialIssue(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改物料领料单';
try {
const res = await getMaterialIssue(_id);
Object.assign(form.value, res.data);
// 确保itemList存在且格式正确
if (!form.value.itemList) {
form.value.itemList = [];
}
// 转换数据类型并计算剩余数量
form.value.itemList = form.value.itemList.map((item) => ({
...item,
stockQuantity: Number(item.stockQuantity) || 0,
issuedQuantity: Number(item.issuedQuantity) || 0,
remainingQuantity: Number(item.remainingQuantity) || 0,
name: item.name || '' // 确保名称不为undefined
}));
// 为每个条目添加监听并强制计算剩余数量
form.value.itemList.forEach((_, index) => {
watchItemChanges(index);
calculateRemaining(index);
});
// 关键编辑时从itemList重新计算设备材料名称覆盖后端返回的旧值
computeMaterialName();
// 手动触发一次验证
setTimeout(() => {
if (materialIssueFormRef.value) {
form.value.itemList.forEach((_, index) => {
materialIssueFormRef.value.validateField(`itemList.${index}.issuedQuantity`);
materialIssueFormRef.value.validateField(`itemList.${index}.remainingQuantity`);
});
// 验证设备材料名称
materialIssueFormRef.value.validateField('materialName');
}
}, 0);
dialog.visible = true;
dialog.title = '修改物料领料单';
} catch (error) {
proxy?.$modal.msgError('获取详情失败');
}
};
/** 提交按钮 */
@ -433,21 +593,38 @@ const submitForm = () => {
materialIssueFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateMaterialIssue(form.value).finally(() => (buttonLoading.value = false));
} else {
await addMaterialIssue(form.value).finally(() => (buttonLoading.value = false));
try {
// 处理提交数据,确保数量为数字类型
const submitData = {
...form.value,
itemList: form.value.itemList.map((item) => ({
...item,
stockQuantity: Number(item.stockQuantity),
issuedQuantity: Number(item.issuedQuantity),
remainingQuantity: Number(item.remainingQuantity)
}))
};
if (form.value.id) {
await updateMaterialIssue(submitData);
} else {
await addMaterialIssue(submitData);
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
} catch (error) {
proxy?.$modal.msgError('操作失败');
} finally {
buttonLoading.value = false;
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
// 添加数量验收条目
const addItem = () => {
form.value.itemList.push({
const newItem = {
id: undefined,
specification: undefined,
unit: undefined,
@ -455,46 +632,81 @@ const addItem = () => {
issuedQuantity: undefined,
remainingQuantity: undefined,
name: undefined,
remark: undefined
});
remark: undefined,
materialsId: undefined
};
form.value.itemList.push(newItem);
// 监听新条目
watchItemChanges(form.value.itemList.length - 1);
// 添加后重新计算材料名称
computeMaterialName();
};
// 删除数量验收条目
const removeItem = (index: number) => {
if (form.value.itemList.length > 1) {
// 停止该条目的监听
if (itemWatchStopFns.value[index]) {
itemWatchStopFns.value[index]();
}
form.value.itemList.splice(index, 1);
itemWatchStopFns.value.splice(index, 1);
// 删除后重新计算材料名称
computeMaterialName();
} else {
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
}
};
/** 删除按钮操作 */
const handleDelete = async (row?: MaterialIssueVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除物料领料单编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delMaterialIssue(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
try {
await proxy?.$modal.confirm(`是否确认删除物料领料单编号为"${_ids}"的数据项?`);
await delMaterialIssue(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
} catch (error) {
// 取消删除不提示
} finally {
loading.value = false;
}
};
const handleView = (row) => {
// 查看详情
wordllssueRef.value?.openDialog(row);
};
// 关键:监听数量验收列表变化,实时更新设备材料名称
watch(
() => form.value.itemList,
() => {
computeMaterialName();
},
{ deep: true, immediate: true } // deep监听数组内部变化immediate初始执行
);
onMounted(() => {
getList();
getName();
});
//监听项目id刷新数据
// 监听项目id刷新数据
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
(nid) => {
queryParams.value.projectId = nid;
form.value.projectId = nid;
getList();
getName();
}
);
onUnmounted(() => {
listeningProject();
// 清理所有监听
itemWatchStopFns.value.forEach((stop) => stop());
});
</script>
<style scoped lang="scss">

View File

@ -1,7 +1,6 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
@ -12,11 +11,10 @@
<el-input v-model="queryParams.projectName" placeholder="请输入工程名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="材料名称" prop="materialName">
<el-input v-model="queryParams.materialName" placeholder="请输入设备材料名称" clearable
@keyup.enter="handleQuery" />
<el-input v-model="queryParams.materialName" placeholder="请输入设备材料名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="合同名称" prop="contractName">
<el-input v-model="queryParams.contractName" placeholder="请输入合同名称" clearable @keyup.enter="handleQuery" />
<el-form-item label="合同编号" prop="contractName">
<el-input v-model="queryParams.contractName" placeholder="请输入合同编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="订货单位" prop="orderingUnit">
<el-input v-model="queryParams.orderingUnit" placeholder="请输入订货单位" clearable @keyup.enter="handleQuery" />
@ -25,11 +23,8 @@
<el-input v-model="queryParams.supplierUnit" placeholder="请输入供货单位" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" v-hasPermi="['materials:materialReceive:list']" icon="Search"
@click="handleQuery">搜索</el-button>
<el-button icon="Refresh" v-hasPermi="['materials:materialReceive:list']"
@click="resetQuery">重置</el-button>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
@ -40,19 +35,14 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd"
v-hasPermi="['materials:materialReceive:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
v-hasPermi="['materials:materialReceive:remove']">删除</el-button>
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['materials:materialReceive:add']">新增</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="materialReceiveList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" width="60" label="序号" align="center" />
<el-table-column label="表单编号" align="center" prop="formCode" />
<el-table-column label="工程名称" align="center" prop="projectName" />
<el-table-column label="设备材料名称" align="center" prop="materialName" />
@ -65,34 +55,40 @@
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<el-table-column label="操作" align="center" min-width="120" fixed="right">
<template #default="scope">
<el-tooltip content="查看" placement="top">
<el-button link type="primary" icon="View" @click="handleView(scope.row)"
v-hasPermi="['materials:materialReceive:query']"></el-button>
</el-tooltip>
<!-- <el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialReceive:edit']"></el-button>
</el-tooltip> -->
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['materials:materialReceive:remove']"></el-button>
</el-tooltip>
<!-- <el-button link type="primary" icon="edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialReceive:edit']"
>修改</el-button
> -->
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['materials:materialReceive:query']"
>查看</el-button
>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materialReceive:remove']"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改物料接收单对话框 -->
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
<el-dialog
:close-on-click-modal="false"
:close-on-press-escape="false"
draggable
:title="dialog.title"
v-model="dialog.visible"
width="800px"
append-to-body
>
<el-form ref="materialReceiveFormRef" :model="form" :rules="rules" label-width="110px">
<el-row>
<el-col :span="12">
<el-form-item label="材料来源" prop="materialSource">
<el-select v-model="form.materialSource" filterable placeholder="请选择材料来源" style="width: 100%">
<el-option label="甲供材料" value="1"></el-option>
<el-option label="供材料" value="2"></el-option>
<el-option label="供材料" value="2"></el-option>
</el-select>
</el-form-item>
</el-col>
@ -101,28 +97,38 @@
<el-input v-model="form.formCode" placeholder="请输入表单编号" />
</el-form-item>
</el-col>
<el-col :span="12"><el-form-item label="采购单编号" prop="docId"><el-select @change="handleSelect"
v-model="form.docId" filterable placeholder="请选择采购单" style="width: 100%">
<el-option v-for="item in purchaseDocList" :key="item.id" :label="item.docCode"
:value="item.id"></el-option> </el-select></el-form-item>
<el-col v-if="form.materialSource == '2'" :span="12">
<el-form-item label="采购单编号" prop="docId">
<el-select @change="handleSelect" v-model="form.docId" filterable placeholder="请选择采购单" style="width: 100%">
<el-option v-for="item in purchaseDocList" :key="item.id" :label="item.docCode" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-col v-if="form.materialSource == '2'" :span="12">
<el-form-item label="供货单位" prop="supplierUnit">
<el-input disabled v-model="form.supplierUnit" placeholder="请输入供货单位" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-col v-if="form.materialSource == '2'" :span="12">
<el-form-item label="订货单位" prop="orderingUnit">
<el-input v-model="form.orderingUnit" placeholder="请输入订货单位" />
</el-form-item>
</el-col>
<el-col :span="12"><el-form-item label="工程名称" prop="projectName">
<el-input v-model="form.projectName" placeholder="请输入工程名称" />
<el-col :span="12">
<el-form-item label="工程名称" prop="projectName">
<el-input disabled v-model="form.projectName" placeholder="请输入工程名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同名称" prop="contractName">
<el-input v-model="form.contractName" placeholder="请输入合同名称" />
<el-form-item label="合同编号" prop="contractName">
<el-select v-model="form.contractName" filterable placeholder="请选择合同" style="width: 100%">
<el-option
v-for="item in contractNameList"
:key="item.contractCode"
:label="item.contractCode"
:value="item.contractCode"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
@ -130,102 +136,109 @@
<el-input v-model="form.defectDescription" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
<!-- 数量验收区域 -->
<el-col :span="24">
<div class="detail">
<div class="detail-header">
<span>数量验收</span>
<!-- <el-button type="primary" link @click="addItem" icon="Plus">添加数量验收</el-button> -->
<el-button type="primary" v-if="form.materialSource == '1'" link @click="addItem" icon="Plus">添加数量验收</el-button>
</div>
<div v-for="(item, index) in form.itemList" :key="index" class="detail-item">
<div v-for="(item, index) in form.itemList" :key="item.id" class="detail-item">
<el-row>
<el-col :span="12">
<el-form-item disabled label="名称" :prop="`itemList.${index}.name`"
:rules="{ required: true, message: '名称不能为空', trigger: 'blur' }">
<el-input disabled v-model="item.name" placeholder="请输入名称" />
<el-form-item label="名称" :prop="`itemList.${index}.name`" :rules="{ required: true, message: '名称不能为空', trigger: 'blur' }">
<el-input :disabled="form.materialSource == '2'" v-model="item.name" placeholder="请输入名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="规格" :prop="`itemList.${index}.specification`"
:rules="{ required: true, message: '规格不能为空', trigger: 'blur' }">
<el-input disabled v-model="item.specification" placeholder="请输入规格" />
<el-form-item
label="规格"
:prop="`itemList.${index}.specification`"
:rules="{ required: true, message: '规格不能为空', trigger: 'blur' }"
>
<el-input :disabled="form.materialSource == '2'" v-model="item.specification" placeholder="请输入规格" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="单位" :prop="`itemList.${index}.unit`"
:rules="{ required: true, message: '单位不能为空', trigger: 'blur' }">
<el-input disabled v-model="item.unit" placeholder="请输入单位" />
<el-form-item label="单位" :prop="`itemList.${index}.unit`" :rules="{ required: true, message: '单位不能为空', trigger: 'blur' }">
<el-input :disabled="form.materialSource == '2'" v-model="item.unit" placeholder="请输入单位" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="数量" :prop="`itemList.${index}.quantity`"
:rules="{ required: true, message: '数量不能为空', trigger: 'blur' }">
<el-input disabled type="number" v-model="item.quantity" placeholder="请输入数量" />
<el-form-item label="数量" :prop="`itemList.${index}.quantity`" :rules="rules.quantityRule" ref="quantityFormItemRefs[index]">
<el-input
:disabled="form.materialSource == '2'"
type="number"
v-model.number="item.quantity"
placeholder="请输入数量"
min="0"
@input="handleQuantityInput(index)"
@blur="handleQuantityBlur(index)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="验收" :prop="`itemList.${index}.acceptedQuantity`"
:rules="{ required: true, message: '验收数量不能为空', trigger: 'blur' }">
<el-input type="number" v-model="item.acceptedQuantity" placeholder="请输入验收" />
<el-form-item label="验收" :prop="`itemList.${index}.acceptedQuantity`" :rules="rules.acceptedQuantityRule">
<el-input
type="number"
v-model.number="item.acceptedQuantity"
placeholder="请输入验收"
min="0"
@input="handleAcceptedInput(index)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="缺件" :prop="`itemList.${index}.shortageQuantity`"
:rules="{ required: true, message: '缺件数量不能为空', trigger: 'blur' }">
<el-input type="number" v-model="item.shortageQuantity" placeholder="自动计算(数量-验收数量)" readonly />
<el-form-item
label="缺件"
:prop="`itemList.${index}.shortageQuantity`"
:rules="{ required: true, message: '缺件数量不能为空', trigger: 'blur' }"
>
<el-input type="number" min="0" v-model="item.shortageQuantity" placeholder="自动计算" readonly />
<span class="tips">*自动计算数量-验收数量</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="item.remark" placeholder="请输入备注" />
<el-col :span="24">
<el-form-item label="备注" :prop="`itemList.${index}.remark`">
<el-input v-model="item.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-col>
<!-- <el-col :span="12" v-if="form.itemList.length > 1">
<el-col :span="12" v-if="form.itemList.length > 1 && form.materialSource == '1'">
<div class="item-actions">
<el-button type="danger" link @click="removeItem(index)" icon="Delete">删除</el-button>
</div>
</el-col> -->
</el-col>
</el-row>
</div>
</div>
</el-col>
<el-col :span="12">
<el-form-item label="合格证文件" prop="certCountFileId">
<file-upload :isShowTip="false" v-model="form.certCountFileId" />
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.certCountFileId" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="出厂报告文件" prop="reportCountFileId">
<file-upload :isShowTip="false" v-model="form.reportCountFileId" />
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.reportCountFileId" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="技术资料文件" prop="techDocCountFileId">
<file-upload :isShowTip="false" v-model="form.techDocCountFileId" />
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.techDocCountFileId" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="厂家资质文件" prop="licenseCountFileId">
<file-upload :isShowTip="false" v-model="form.licenseCountFileId" />
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.licenseCountFileId" />
</el-form-item>
</el-col>
<el-col :span="24">
<span
style="color: #ff0000ab; margin-bottom: 10px; display: block">注意请上传doc/xls/ppt/txt/pdf/png/jpg/jpeg/zip格式文件</span>
<span style="color: #ff0000ab; margin-bottom: 10px; display: block">注意pdf/png/jpg/jpeg格式文件</span>
</el-col>
<el-col :span="24">
<el-form-item label="设备材料入库/移交" prop="storageType">
<el-radio-group v-model="form.storageType">
<el-radio v-for="dict in storage_type.slice(0, 1)" :key="dict.value" :label="dict.value">
{{ dict.label }}
</el-radio>
</el-radio-group>
<!-- <el-checkbox-group v-model="form.storageType">
<el-checkbox v-for="dict in storage_type" :key="dict.value" :label="dict.value">
{{ dict.label }}
</el-checkbox>
</el-checkbox-group> -->
</el-form-item> </el-col><el-col :span="24"><el-form-item label="备注" prop="remark">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
@ -248,21 +261,28 @@ import {
getMaterialReceive,
delMaterialReceive,
addMaterialReceive,
updateMaterialReceive
updateMaterialReceive,
getContractNameList
} from '@/api/materials/materialReceive';
import { MaterialReceiveVO, MaterialReceiveQuery, MaterialReceiveForm } from '@/api/materials/materialReceive/types';
import { useUserStoreHook } from '@/store/modules/user';
import wordllReceive from './word/index.vue';
import { listPurchaseDoc, purchaseDocPlanList } from '@/api/materials/purchaseDoc';
import { watch } from 'vue';
import { watch, onMounted, onUnmounted, ref, reactive, computed, toRefs, getCurrentInstance } from 'vue';
import type { ComponentInternalInstance, ElFormInstance, DialogOption, ElFormItem } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { storage_type } = toRefs<any>(proxy?.useDict('storage_type'));
// 获取用户 store
const userStore = useUserStoreHook();
// 从 store 中获取项目列表和当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
const wordllReceiveRef = ref<InstanceType<typeof wordllReceive>>();
// 存储每个验收条目的watch停止函数
const itemWatchStopFns = ref<Array<() => void>>([]);
// 存储数量表单项的引用,用于手动触发验证
const quantityFormItemRefs = ref<(ElFormItem | null)[]>([]);
// 列表数据
const materialReceiveList = ref<MaterialReceiveVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
@ -272,15 +292,26 @@ const single = ref(true);
const multiple = ref(true);
const total = ref(0);
// 表单引用
const queryFormRef = ref<ElFormInstance>();
const materialReceiveFormRef = ref<ElFormInstance>();
const purchaseDocList = ref([]); //物资采购单
const purchaseMap = new Map();
const purchaseDocList = ref([]); // 物资采购单列表
const purchaseMap = new Map(); // 采购单映射id -> 采购单对象)
const contractNameList = ref([]); //合同列表
// 对话框配置
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const getInitFormData = () => {
// 生成验收条目唯一ID
const generateItemId = () => {
return Date.now() + Math.random().toString(36).substr(2, 9);
};
// 初始化表单数据
const getInitFormData = (): MaterialReceiveForm => {
return {
id: undefined,
projectId: currentProject.value?.id,
@ -300,12 +331,13 @@ const getInitFormData = () => {
techDocCountFileId: undefined,
licenseCount: undefined,
licenseCountFileId: undefined,
storageType: '',
storageType: '1',
remark: undefined,
docId: undefined,
docCode: undefined,
itemList: [
{
id: generateItemId(),
name: undefined,
specification: undefined,
unit: undefined,
@ -317,7 +349,8 @@ const getInitFormData = () => {
]
};
};
const initFormData: MaterialReceiveForm = {};
// 响应式数据
const data = reactive({
form: getInitFormData(),
queryParams: {
@ -334,18 +367,42 @@ const data = reactive({
params: {}
},
rules: {
// 物资采购单
docId: [{ required: true, message: '请选择物资采购单', trigger: 'change' }],
// 材料来源
materialSource: [{ required: true, message: '请选择材料来源', trigger: 'change' }],
// 表单编号
formCode: [{ required: true, message: '请输入表单编号', trigger: 'blur' }],
// 采购单编号
docCode: [{ required: true, message: '请输入采购单编号', trigger: 'blur' }],
// 供货单位
docId: [{ required: true, message: '请选择物资采购单', trigger: 'change' }],
supplierUnit: [{ required: true, message: '请输入供货单位', trigger: 'blur' }],
// 订货单位
orderingUnit: [{ required: true, message: '请输入订货单位', trigger: 'blur' }]
orderingUnit: [{ required: true, message: '请输入订货单位', trigger: 'blur' }],
// 数量校验规则确保触发时机包含change且类型为number
quantityRule: [
{ required: true, message: '数量不能为空', trigger: ['blur', 'change'] },
{ type: 'number', min: 0, message: '数量不能小于0', trigger: ['blur', 'change'] }
],
// 验收数量规则(允许≤数量)
acceptedQuantityRule: [
{ required: true, message: '验收数量不能为空', trigger: ['blur', 'change'] },
{ type: 'number', min: 0, message: '验收数量不能小于0', trigger: ['blur', 'change'] },
{
validator: (rule, value, callback) => {
const prop = rule.field;
const index = Number(prop.split('.')[1]);
const quantity = Number(form.value.itemList[index].quantity) || 0;
// 数量未填写时不验证大小关系数量有值但验收数量未填时也不阻断由required规则处理
if (form.value.itemList[index].quantity === undefined || form.value.itemList[index].quantity === null) {
callback();
return;
}
// 处理value为undefined/null的情况避免Number(undefined)转为NaN
const acceptedVal = Number(value) || 0;
if (acceptedVal > quantity) {
callback(new Error('验收数量必须小于等于数量'));
} else {
callback();
}
},
trigger: ['blur', 'change']
}
]
}
});
@ -354,10 +411,19 @@ const { queryParams, form, rules } = toRefs(data);
/** 查询物料接收单列表 */
const getList = async () => {
loading.value = true;
const res = await listMaterialReceive(queryParams.value);
materialReceiveList.value = res.rows;
total.value = res.total;
loading.value = false;
try {
const res = await listMaterialReceive(queryParams.value);
materialReceiveList.value = res.rows;
total.value = res.total;
} finally {
loading.value = false;
}
};
// 获取合同列表数据
const getContractList = async () => {
let res = await getContractNameList(currentProject.value?.id);
contractNameList.value = res.rows;
};
/** 取消按钮 */
@ -368,8 +434,19 @@ const cancel = () => {
/** 表单重置 */
const reset = () => {
// 停止所有验收条目的watch监听
itemWatchStopFns.value.forEach((stopFn) => stopFn());
itemWatchStopFns.value = [];
form.value = getInitFormData();
materialReceiveFormRef.value?.resetFields();
if (materialReceiveFormRef.value) {
materialReceiveFormRef.value.resetFields();
}
// 重新监听初始条目
if (form.value.itemList.length > 0) {
watchItemChanges(0);
}
};
/** 搜索按钮操作 */
@ -380,14 +457,16 @@ const handleQuery = () => {
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
if (queryFormRef.value) {
queryFormRef.value.resetFields();
}
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: MaterialReceiveVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
single.value = selection.length !== 1;
multiple.value = !selection.length;
};
@ -396,25 +475,45 @@ const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = '添加物料接收单';
// 为初始条目添加监听
if (form.value.itemList.length > 0) {
watchItemChanges(0);
}
form.value.projectName = currentProject.value?.name;
};
/** 修改按钮操作 */
/** 修改按钮操作(核心修复:赋值后主动触发验证+数据类型转换) */
const handleUpdate = async (row?: MaterialReceiveVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await getMaterialReceive(_id);
Object.assign(form.value, res.data);
// 为每个条目添加监听
form.value.itemList.forEach((_, index) => {
watchItemChanges(index);
});
dialog.visible = true;
dialog.title = '修改物料接收单';
try {
const res = await getMaterialReceive(_id);
const formData = res.data;
// 修复1处理itemList数据类型确保数量/验收数量为数字避免字符串与number规则冲突
formData.itemList = formData.itemList.map((item) => ({
...item,
id: item.id || generateItemId(),
quantity: item.quantity !== undefined ? Number(item.quantity) : undefined, // 转为数字
acceptedQuantity: item.acceptedQuantity !== undefined ? Number(item.acceptedQuantity) : undefined, // 转为数字
shortageQuantity: item.shortageQuantity !== undefined ? Number(item.shortageQuantity) : undefined // 转为数字
}));
Object.assign(form.value, formData);
// 修复2重新监听所有条目并主动触发每个条目的验证更新验证状态
form.value.itemList.forEach((_, index) => {
watchItemChanges(index);
// 手动触发当前条目的数量、验收数量、缺件数量验证
if (materialReceiveFormRef.value) {
materialReceiveFormRef.value.validateField(`itemList.${index}.quantity`, () => {});
materialReceiveFormRef.value.validateField(`itemList.${index}.acceptedQuantity`, () => {});
materialReceiveFormRef.value.validateField(`itemList.${index}.shortageQuantity`, () => {});
}
});
dialog.visible = true;
dialog.title = '修改物料接收单';
} catch (err) {
proxy?.$modal.msgError('获取详情失败');
}
};
/** 提交按钮 */
@ -422,14 +521,32 @@ const submitForm = () => {
materialReceiveFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateMaterialReceive({ ...form.value }).finally(() => (buttonLoading.value = false));
} else {
await addMaterialReceive({ ...form.value }).finally(() => (buttonLoading.value = false));
try {
// 提交前确保数据类型正确(数字)
const submitForm = {
...form.value,
itemList: form.value.itemList.map((item) => ({
...item,
quantity: Number(item.quantity),
acceptedQuantity: Number(item.acceptedQuantity),
shortageQuantity: Number(item.shortageQuantity)
}))
};
if (form.value.id) {
await updateMaterialReceive(submitForm);
} else {
submitForm.itemList.forEach((item) => {
delete item.id;
});
await addMaterialReceive(submitForm);
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
} finally {
buttonLoading.value = false;
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
@ -437,15 +554,24 @@ const submitForm = () => {
/** 删除按钮操作 */
const handleDelete = async (row?: MaterialReceiveVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除物料接收单编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delMaterialReceive(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
if (!_ids.length) return;
try {
await proxy?.$modal.confirm(`是否确认删除物料接收单编号为"${_ids}"的数据项?`);
await delMaterialReceive(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
} catch (err) {
// 取消删除时不提示
} finally {
loading.value = false;
}
};
// 添加数量验收条目
/** 添加数量验收条目 */
const addItem = () => {
const newItem = {
id: generateItemId(),
name: undefined,
specification: undefined,
unit: undefined,
@ -455,110 +581,243 @@ const addItem = () => {
remark: undefined
};
form.value.itemList.push(newItem);
// 监听新条目数据变化
// 监听新条目变化并触发初始验证
watchItemChanges(form.value.itemList.length - 1);
validateQuantityField(form.value.itemList.length - 1);
};
// 监听条目数据变化,自动计算缺件数量
const watchItemChanges = (index: number) => {
watch(
() => [form.value.itemList[index].quantity, form.value.itemList[index].acceptedQuantity],
([quantity, acceptedQuantity]) => {
// 确保数量和验收数量都是数字
const qty = Number(quantity) || 0;
const acceptedQty = Number(acceptedQuantity) || 0;
// 计算缺件数量(数量 - 验收数量)
form.value.itemList[index].shortageQuantity = qty - acceptedQty;
},
{ immediate: true }
);
// 数量输入事件处理
const handleQuantityInput = (index: number) => {
// 确保值为数字类型
if (form.value.itemList[index].quantity !== undefined) {
form.value.itemList[index].quantity = Number(form.value.itemList[index].quantity);
}
// 手动触发验证
validateQuantityField(index);
};
// 删除数量验收条目
const removeItem = (index: number) => {
if (form.value.itemList.length > 1) {
form.value.itemList.splice(index, 1);
} else {
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
// 数量失焦事件
const handleQuantityBlur = (index: number) => {
validateQuantityField(index);
};
// 验收数量输入事件
const handleAcceptedInput = (index: number) => {
// 确保值为数字类型
if (form.value.itemList[index].acceptedQuantity !== undefined) {
form.value.itemList[index].acceptedQuantity = Number(form.value.itemList[index].acceptedQuantity);
}
// 手动触发相关字段验证
validateQuantityField(index);
};
// 手动验证数量和验收数量字段
const validateQuantityField = (index: number) => {
if (materialReceiveFormRef.value) {
materialReceiveFormRef.value.validateField(`itemList.${index}.quantity`, () => {});
materialReceiveFormRef.value.validateField(`itemList.${index}.acceptedQuantity`, () => {});
materialReceiveFormRef.value.validateField(`itemList.${index}.shortageQuantity`, () => {});
}
};
const handleView = (row) => {
// 查看详情
// 监听条目变化,自动计算缺件数量(修复:计算后触发验证)
const watchItemChanges = (index: number) => {
if (itemWatchStopFns.value[index]) {
itemWatchStopFns.value[index]();
}
const stopFn = watch(
() => [form.value.itemList[index].quantity, form.value.itemList[index].acceptedQuantity],
([quantity, acceptedQuantity]) => {
const qty = Number(quantity) || 0;
let acceptedQty = Number(acceptedQuantity) || 0;
// 仅当验收数量>数量时才修正(允许等于)
if (acceptedQty > qty && qty > 0) {
acceptedQty = qty; // 修正为数量值(最大合法值)
form.value.itemList[index].acceptedQuantity = acceptedQty;
proxy?.$modal.msgWarning(`验收数量不能大于数量,已自动修正为${acceptedQty}`);
}
// 计算缺件数量允许为0
form.value.itemList[index].shortageQuantity = qty - acceptedQty;
// 修复3计算后触发当前条目的验证确保缺件数量状态更新
validateQuantityField(index);
},
{ immediate: true }
);
itemWatchStopFns.value[index] = stopFn;
};
/** 删除数量验收条目 */
const removeItem = (index: number) => {
if (form.value.itemList.length <= 1) {
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
return;
}
// 停止该条目的监听
if (itemWatchStopFns.value[index]) {
itemWatchStopFns.value[index]();
}
// 删除条目和对应的停止函数
form.value.itemList.splice(index, 1);
itemWatchStopFns.value.splice(index, 1);
quantityFormItemRefs.value.splice(index, 1);
};
/** 查看详情 */
const handleView = (row: MaterialReceiveVO) => {
wordllReceiveRef.value?.openDialog(row);
};
/** 查询物资-采购联系单列表 */
const getlistPurchase = async () => {
const res = await listPurchaseDoc({
projectId: currentProject.value?.id,
status: 'finish'
});
purchaseDocList.value = res.rows;
if (purchaseDocList.value && purchaseDocList.value.length > 0) {
try {
const res = await listPurchaseDoc({
projectId: currentProject.value?.id,
status: 'finish'
});
purchaseDocList.value = res.rows;
purchaseDocList.value.forEach((item) => {
purchaseMap.set(item.id, item);
});
} catch (err) {
proxy?.$modal.msgError('获取采购单列表失败');
}
};
// 通过采购单获取需求信息
/** 通过采购单获取需求信息(修复:数据类型转换) */
const getdemandInfo = async (docId: string) => {
let res = await purchaseDocPlanList(docId);
if (res.code == 200) {
// 需求表单赋值
form.value.itemList = [];
// form.value.itemList 清空
console.log(form.value.itemList);
res.data.forEach((item, index) => {
let obj = {
quantity: item.demandQuantity,
acceptedQuantity: 0,
shortageQuantity: item.demandQuantity, // 初始化缺件数量为总数量
planId: item.id,
...item
};
obj.id = null;
form.value.itemList.push(obj);
// 监听每个条目的变化
watchItemChanges(form.value.itemList.length - 1);
});
if (!docId) return;
try {
const res = await purchaseDocPlanList(docId);
if (res.code === 200) {
// 清空旧监听和条目
itemWatchStopFns.value.forEach((stopFn) => stopFn());
itemWatchStopFns.value = [];
quantityFormItemRefs.value = [];
form.value.itemList = [];
// 赋值需求数据并添加监听(确保数量为数字)
res.data.forEach((item, index) => {
const qty = Number(item.demandQuantity) || 0;
const newItem = {
id: generateItemId(),
name: item.name,
specification: item.specification,
unit: item.unit,
quantity: qty, // 确保数字类型
acceptedQuantity: 0, // 初始值为0数字
shortageQuantity: qty, // 初始缺件=数量(数字)
remark: item.remark,
planId: item.id,
id: null
};
form.value.itemList.push(newItem);
watchItemChanges(index);
});
}
} catch (err) {
proxy?.$modal.msgError('获取采购单需求信息失败');
}
};
const handleSelect = (val) => {
// 选择设备
let obj = purchaseMap.get(val);
/** 选择采购单触发 */
const handleSelect = (val: string) => {
if (!val) return;
const obj = purchaseMap.get(val);
if (obj) {
form.value.docCode = obj.docCode || '';
form.value.supplierUnit = obj.supplier || '';
form.value.materialName = obj.name || '';
}
getdemandInfo(val);
form.value.docCode = obj?.docCode || '';
form.value.supplierUnit = obj?.supplier || '';
form.value.materialName = obj?.name || '';
};
/** 监听材料来源变化,重置数量验收列表 */
watch(
() => form.value.materialSource,
(newSource, oldSource) => {
if (newSource === oldSource) return;
// 停止所有验收条目的监听
itemWatchStopFns.value.forEach((stopFn) => stopFn());
itemWatchStopFns.value = [];
quantityFormItemRefs.value = [];
// 清空所有文件上传字段的值
form.value.certCountFileId = undefined; // 合格证文件
form.value.reportCountFileId = undefined; // 出厂报告文件
form.value.techDocCountFileId = undefined; // 技术资料文件
form.value.licenseCountFileId = undefined; // 厂家资质文件
// 重置数量验收列表为初始状态
form.value.itemList = [
{
id: generateItemId(),
name: undefined,
specification: undefined,
unit: undefined,
quantity: undefined,
acceptedQuantity: undefined,
shortageQuantity: undefined,
remark: undefined
}
];
// 重新监听初始条目并触发验证
watchItemChanges(0);
validateQuantityField(0);
// 切换到乙供时,清空采购单相关数据
if (newSource === '2') {
form.value.docId = undefined;
form.value.supplierUnit = undefined;
form.value.materialName = undefined;
form.value.docCode = undefined;
}
},
{ immediate: true }
);
/** 页面挂载时初始化 */
onMounted(() => {
getContractList();
getList();
getlistPurchase();
// 为初始条目添加监听
// 监听初始验收条目并触发验证
if (form.value.itemList.length > 0) {
watchItemChanges(0);
validateQuantityField(0);
}
});
// 监听项目id刷新数据
/** 监听项目变化,刷新数据 */
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
(nid) => {
queryParams.value.projectId = nid;
form.value.projectId = nid;
getContractList();
getList();
getlistPurchase();
}
);
/** 页面卸载时清理监听 */
onUnmounted(() => {
listeningProject();
itemWatchStopFns.value.forEach((stopFn) => stopFn());
});
</script>
<style scoped lang="scss">
.detail {
border-bottom: 1px solid #ececec;
@ -599,4 +858,8 @@ onUnmounted(() => {
color: #666;
margin-left: 8px;
}
.mb8 {
margin-bottom: 8px;
}
</style>

View File

@ -1,20 +1,16 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="材料名称" prop="materialsName">
<el-input v-model="queryParams.materialsName" placeholder="请输入材料名称" clearable
@keyup.enter="handleQuery" />
<el-input v-model="queryParams.materialsName" placeholder="请输入材料名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" v-hasPermi="['materials:materialsInventory:list']" icon="Search"
@click="handleQuery">搜索</el-button>
<el-button type="primary" v-hasPermi="['materials:materialsInventory:list']" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" v-hasPermi="['materials:materialsInventory:list']"
@click="resetQuery">重置</el-button>
<el-button icon="Refresh" v-hasPermi="['materials:materialsInventory:list']" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
@ -25,8 +21,7 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport"
v-hasPermi="['materials:materialsInventory:export']">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['materials:materialsInventory:export']">
导出
</el-button>
</el-col>
@ -45,8 +40,13 @@
<el-table-column label="使用部位" align="center" prop="usePart" />
<el-table-column label="备注" align="center" prop="remark" />
</el-table>
<pagination v-show="totalChild > 0" :total="totalChild" v-model:page="queryParamsChild.pageNum"
v-model:limit="queryParamsChild.pageSize" @pagination="getListChild" />
<pagination
v-show="totalChild > 0"
:total="totalChild"
v-model:page="queryParamsChild.pageNum"
v-model:limit="queryParamsChild.pageSize"
@pagination="getListChild"
/>
</div>
</template>
</el-table-column>
@ -115,8 +115,7 @@
</template>
</el-table-column> -->
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改材料出/入库对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
@ -130,8 +129,7 @@
<el-input v-model="form.number" placeholder="请输入出/入库的数量" />
</el-form-item>
<el-form-item label="出/入库操作时间" prop="outPutTime">
<el-date-picker clearable v-model="form.outPutTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择出/入库操作时间">
<el-date-picker clearable v-model="form.outPutTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择出/入库操作时间">
</el-date-picker>
</el-form-item>
<el-form-item label="剩余库存数量" prop="residue">
@ -176,9 +174,7 @@ import {
} from '@/api/materials/materialsInventory';
import { MaterialsInventoryForm, MaterialsInventoryQuery, MaterialsInventoryVO } from '@/api/materials/materialsInventory/types';
import { useUserStoreHook } from '@/store/modules/user';
import {
listMaterialsUseRecord,
} from '@/api/materials/materialsUseRecord';
import { listMaterialsUseRecord } from '@/api/materials/materialsUseRecord';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { out_put_type } = toRefs<any>(proxy?.useDict('out_put_type'));

View File

@ -1,7 +1,6 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave"> </transition>
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> </transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
@ -19,8 +18,7 @@
</template>
<!-- 外层表格添加ref用于控制展开状态 -->
<el-table ref="outerTableRef" v-loading="loading" :data="materialsUseInventoryList"
@expand-change="handleExpandChange" border>
<el-table ref="outerTableRef" v-loading="loading" :data="materialsUseInventoryList" @expand-change="handleExpandChange" border>
<el-table-column type="expand">
<template #default="props">
<div style="margin-left: 60px">
@ -32,13 +30,25 @@
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="delete" v-if="scope.row.ishow" @click="handleDelete(scope.row)"
v-hasPermi="['materials:materialsUseRecord:remove']">删除</el-button>
<el-button
link
type="primary"
icon="delete"
v-if="scope.row.ishow"
@click="handleDelete(scope.row)"
v-hasPermi="['materials:materialsUseRecord:remove']"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<pagination v-show="totalChild > 0" :total="totalChild" v-model:page="queryParamsChild.pageNum"
v-model:limit="queryParamsChild.pageSize" @pagination="getListChild" />
<pagination
v-show="totalChild > 0"
:total="totalChild"
v-model:page="queryParamsChild.pageNum"
v-model:limit="queryParamsChild.pageSize"
@pagination="getListChild"
/>
</div>
</template>
</el-table-column>
@ -53,13 +63,13 @@
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)"
v-hasPermi="['materials:materialsUseRecord:add']">添加登记</el-button>
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['materials:materialsUseRecord:add']"
>添加登记</el-button
>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改材料使用登记对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>

View File

@ -6,10 +6,10 @@
<el-row :gutter="10" class="mb8">
<el-form :inline="true">
<el-form-item v-if="state.masterData.status == 'draft'">
<el-button type="primary" v-hasPermi="['design:totalsupplyplan:queryList']" icon="edit" @click="clickApprovalSheet1()">审批</el-button>
<el-button type="primary" icon="edit" @click="clickApprovalSheet1()">审批</el-button>
</el-form-item>
<el-form-item v-if="state.masterData.status == 'waiting' || state.masterData.status == 'finish'">
<el-button icon="view" v-hasPermi="['design:totalsupplyplan:queryList']" @click="lookApprovalFlow()" type="warning">查看流程</el-button>
<el-button icon="view" @click="lookApprovalFlow()" type="warning">查看流程</el-button>
</el-form-item>
</el-form>
<right-toolbar @queryTable="getMasterDataList"></right-toolbar>

View File

@ -110,18 +110,15 @@
>修改</el-button
>
<el-button
link
type="primary"
v-if="scope.row.status == 'finish' && scope.row.feedbackUrl"
icon="Share"
@click="handleShare(scope.row)"
v-hasPermi="['cailiaoshebei:purchaseDoc:list']"
<el-button link type="primary" v-if="scope.row.status == 'finish' && scope.row.feedbackUrl" icon="Share" @click="handleShare(scope.row)"
>物流单分享</el-button
>
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['cailiaoshebei:purchaseDoc:remove']"
>详情</el-button
>
<el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['cailiaoshebei:purchaseDoc:downloadWord']"
>下载</el-button
>
</template>
</el-table-column>
</el-table>
@ -136,8 +133,8 @@
></el-col>
<el-col :span="12" :offset="0"
><el-form-item label="供应商" prop="supplier">
<el-select v-model="form.supplier" value-key="id" placeholder="请选择供应商" clearable filterable @change="">
<el-option v-for="item in supplierOptions" :key="item.id" :label="item.name" :value="item.name"> </el-option>
<el-select v-model="form.supplierId" value-key="id" placeholder="请选择供应商" clearable filterable @change="">
<el-option v-for="item in supplierOptions" :key="item.id" :label="item.supplierName" :value="item.id"> </el-option>
</el-select> </el-form-item
></el-col>
<el-col :span="12" :offset="0"
@ -232,7 +229,9 @@
<el-table-column label="物资名称" align="center" prop="name" />
<el-table-column label="规格型号" align="center" prop="specification">
<template #default="scope">
<el-button link type="primary" icon="Finished" @click="getDetailList(scope.row.ltn)"> 查看物流信息</el-button></template
<el-button link type="primary" icon="Finished" v-hasPermi="['cailiaoshebei:ltn:logistics']" @click="getDetailList(scope.row.ltn)">
查看物流信息</el-button
></template
>
</el-table-column>
</el-table>
@ -268,6 +267,8 @@ import { listContractor } from '@/api/project/contractor';
import { useUserStoreHook } from '@/store/modules/user';
import { getToken } from '@/utils/auth';
import logisticsDetail from './comm/logisticsDetail.vue';
import { FormRules } from 'element-plus';
import { listSupplierInput } from '@/api/supplierInput/supplierInput';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const route = useRoute();
const router = useRouter();
@ -307,6 +308,8 @@ const initFormData: any = {
docCode: undefined,
supplier: undefined,
reason: undefined,
supplierId: undefined,
name: undefined,
arrivalDate: undefined,
designDirectorTel: undefined,
@ -349,7 +352,7 @@ const data = reactive({
status: undefined,
params: {}
},
rules: {
rules: <FormRules>{
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
docCode: [{ required: true, message: '采购单编号不能为空', trigger: 'blur' }],
planId: [{ required: true, message: '需求计划不能为空', trigger: 'blur' }],
@ -382,6 +385,15 @@ const cancel = () => {
reset();
dialog.visible = false;
};
const handleDownload = async (row) => {
proxy?.download(
'/cailiaoshebei/purchaseDoc/export/word',
{
id: row.id
},
`${row.docCode}.doc`
);
};
const handleDetail = async (row?: PurchaseDocVO) => {
proxy?.$modal.loading('加载中');
@ -470,6 +482,7 @@ const submitForm = () => {
form.value.associationList = form.value.planId?.map((item: any) => ({
planId: item
}));
form.value.supplier = supplierOptions.value.find((item) => item.id == form.value.supplierId)?.supplierName;
if (form.value.id) {
await updatePurchaseDoc(form.value).finally(() => (buttonLoading.value = false));
@ -505,10 +518,10 @@ const getBatchList = async () => {
};
const getSupplierList = async () => {
const res = await listContractor({
const res = await listSupplierInput({
projectId: currentProject.value?.id,
pageNum: 1,
contractorType: 4,
state: 'finish',
pageSize: 10000
});
supplierOptions.value = res.rows;

View File

@ -23,7 +23,7 @@
style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)"
:row-class-name="tableRowClassName"
>
<el-table-column prop="id" label="ID" width="180" align="center"></el-table-column>
<el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
<el-table-column prop="name" label="材料名称" min-width="150"></el-table-column>
<el-table-column prop="specification" label="规格" min-width="120"></el-table-column>
<el-table-column prop="supplier" label="供应商" min-width="150"></el-table-column>
@ -45,31 +45,29 @@
{{ formatDate(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" fixed="right">
<el-table-column label="操作" width="240" align="center" fixed="right">
<template #default="scope">
<!-- <el-button size="small" icon="Plus" @click="handleAddSon(scope.row)"
class="text-blue-600 hover:text-blue-800 transition-colors"></el-button> -->
<el-button
size="small"
v-hasPermi="['cailiaoshebei:physicalsupply:edit']"
icon="Edit"
@click="handleEdit(scope.row)"
class="text-blue-600 hover:text-blue-800 transition-colors"
></el-button>
<el-button size="small" v-hasPermi="['cailiaoshebei:physicalsupply:edit']" icon="Edit" type="primary" link @click="handleEdit(scope.row)"
>修改</el-button
>
<el-button
size="small"
type="primary"
v-hasPermi="['cailiaoshebei:physicalsupplySon:list']"
icon="View"
link
@click="jumpRouter(scope.row)"
class="text-blue-600 hover:text-blue-800 transition-colors"
></el-button>
>查看</el-button
>
<el-button
size="small"
type="primary"
link
v-hasPermi="['cailiaoshebei:physicalsupply:remove']"
icon="Delete"
@click="handleDelete(scope.row)"
class="text-red-600 hover:text-red-800 transition-colors"
></el-button>
>删除</el-button
>
</template>
</el-table-column>
</el-table>

View File

@ -1,22 +1,36 @@
<template>
<div style="padding: 20px">
<el-card class="mb-5">
<el-button type="primary" v-hasPermi="['cailiaoshebei:physicalsupply:add']" icon="Plus" @click="handleAdd"
class="transition-all duration-200 hover:shadow-md">
<el-button
type="primary"
v-hasPermi="['cailiaoshebei:physicalsupply:add']"
icon="Plus"
@click="handleAdd"
class="transition-all duration-200 hover:shadow-md"
>
新增
</el-button>
<el-button v-hasPermi="['cailiaoshebei:physicalsupply:list']" icon="Refresh" @click="refreshData"
class="transition-all duration-200 hover:shadow-md">
<el-button
v-hasPermi="['cailiaoshebei:physicalsupply:list']"
icon="Refresh"
@click="refreshData"
class="transition-all duration-200 hover:shadow-md"
>
刷新
</el-button>
</el-card>
<!-- 数据表格 -->
<div class="bg-white rounded-lg shadow-sm overflow-hidden transition-all duration-300 hover:shadow-md">
<el-table v-loading="loading" :data="tableData" border stripe
<el-table
v-loading="loading"
:data="tableData"
border
stripe
style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)"
:header-cell-style="{ 'background-color': '#f5f7fa', 'font-weight': 'bold' }"
:row-class-name="tableRowClassName">
:row-class-name="tableRowClassName"
>
<!-- <el-table-column prop="id" label="ID" width="180" align="center"></el-table-column> -->
<el-table-column type="index" label="序号" align="center" width="60"></el-table-column>
@ -41,27 +55,53 @@
{{ formatDate(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column label="操作" width="240" align="center" fixed="right">
<el-table-column label="操作" width="300" align="center" fixed="right">
<template #default="scope">
<el-button v-hasPermi="['cailiaoshebei:physicalsupplySon:add']" size="small" icon="Plus"
@click="handleAddSon(scope.row)" class="text-blue-600 hover:text-blue-800 transition-colors"></el-button>
<el-button v-hasPermi="['cailiaoshebei:physicalsupply:edit']" size="small" icon="Edit"
@click="handleEdit(scope.row)" class="text-blue-600 hover:text-blue-800 transition-colors"></el-button>
<el-button v-hasPermi="['cailiaoshebei:physicalsupplySon:list']" size="small" icon="View"
@click="jumpRouter(scope.row)" class="text-blue-600 hover:text-blue-800 transition-colors"></el-button>
<el-button v-hasPermi="['cailiaoshebei:physicalsupply:remove']" size="small" icon="Delete"
@click="handleDelete(scope.row)" class="text-red-600 hover:text-red-800 transition-colors"></el-button>
<el-button
v-hasPermi="['cailiaoshebei:physicalsupplySon:add']"
size="small"
icon="Plus"
type="primary"
link
@click="handleAddSon(scope.row)"
>添加</el-button
>
<el-button type="primary" v-hasPermi="['cailiaoshebei:physicalsupply:edit']" size="small" icon="Edit" link @click="handleEdit(scope.row)"
>修改</el-button
>
<el-button
type="primary"
v-hasPermi="['cailiaoshebei:physicalsupplySon:list']"
size="small"
icon="View"
link
@click="jumpRouter(scope.row)"
>查看</el-button
>
<el-button
v-hasPermi="['cailiaoshebei:physicalsupply:remove']"
size="small"
icon="Delete"
link
type="primary"
@click="handleDelete(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="fetchData" />
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="fetchData" />
</div>
<!-- 新增/编辑对话框 -->
<el-dialog v-model="dialogVisible" :title="dialogType === 'add' ? '新增记录' : '编辑记录'" :width="dialogWidth"
:fullscreen="isFullscreen" :before-close="handleDialogClose">
<el-dialog
v-model="dialogVisible"
:title="dialogType === 'add' ? '新增记录' : '编辑记录'"
:width="dialogWidth"
:fullscreen="isFullscreen"
:before-close="handleDialogClose"
>
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px" class="space-y-4">
<el-row :gutter="20">
<el-col :span="12">
@ -105,8 +145,12 @@
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="合同签订时间" prop="contractSigning">
<el-date-picker v-model="formData.contractSigning" type="datetime" placeholder="选择合同签订时间"
value-format="YYYY-MM-DD HH:mm:ss"></el-date-picker>
<el-date-picker
v-model="formData.contractSigning"
type="datetime"
placeholder="选择合同签订时间"
value-format="YYYY-MM-DD HH:mm:ss"
></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
@ -119,8 +163,7 @@
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="供货要求" prop="supplyRequirements">
<el-input v-model="formData.supplyRequirements" placeholder="请输入供货要求" type="textarea"
:rows="3"></el-input>
<el-input v-model="formData.supplyRequirements" placeholder="请输入供货要求" type="textarea" :rows="3"></el-input>
</el-form-item>
</el-col>
</el-row>

View File

@ -0,0 +1,256 @@
<template>
<div class="p-2">
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="查看时间" prop="viewTime">
<el-date-picker clearable v-model="queryParams.viewTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择查看时间" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="noticeList">
<el-table-column type="index" label="序号" width="80" align="center" />
<!-- <el-table-column label="接收通知的用户" align="center" prop="recipientId" />
<el-table-column label="发送通知的用户" align="center" prop="senderId" /> -->
<el-table-column label="通知内容" align="center" prop="msg" />
<el-table-column label="查看状态" align="center" prop="viewStatus">
<template #default="scope">
<el-tag :type="scope.row.viewStatus === 0 ? 'danger' : 'success'">{{ scope.row.viewStatus === 0 ? '未读' : '已读' }}</el-tag>
</template>
</el-table-column>
<!-- <el-table-column label="查看时间" align="center" prop="viewTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.viewTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" /> -->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope"> <el-button link type="primary" @click="handleRoute(scope.row)">查看</el-button></template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改消息对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="noticeFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="项目ID" prop="projectId">
<el-input v-model="form.projectId" placeholder="请输入项目ID" />
</el-form-item>
<el-form-item label="接收通知的用户ID" prop="recipientId">
<el-input v-model="form.recipientId" placeholder="请输入接收通知的用户ID" />
</el-form-item>
<el-form-item label="发送通知的用户ID" prop="senderId">
<el-input v-model="form.senderId" placeholder="请输入发送通知的用户ID" />
</el-form-item>
<el-form-item label="配置id" prop="configId">
<el-input v-model="form.configId" placeholder="请输入配置id" />
</el-form-item>
<el-form-item label="详情id" prop="detailId">
<el-input v-model="form.detailId" placeholder="请输入详情id" />
</el-form-item>
<el-form-item label="通知内容">
<editor v-model="form.content" :min-height="192" />
</el-form-item>
<el-form-item label="查看时间" prop="viewTime">
<el-date-picker clearable v-model="form.viewTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择查看时间">
</el-date-picker>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Notice" lang="ts">
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from '@/api/message/notice';
import { NoticeVO, NoticeQuery, NoticeForm } from '@/api/message/notice/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
import { useUserStoreHook } from '@/store/modules/user';
const noticeList = ref([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
// 获取用户 store
const userStore = useUserStoreHook();
// 从 store 中获取项目列表和当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
const queryFormRef = ref<ElFormInstance>();
const noticeFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: NoticeForm = {
id: undefined,
projectId: currentProject.value?.id,
recipientId: undefined,
senderId: undefined,
configId: undefined,
detailId: undefined,
content: undefined,
viewStatus: undefined,
viewTime: undefined,
remark: undefined
};
const data = reactive({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
projectId: currentProject.value?.id,
userId: userStore.userId,
recipientId: undefined,
senderId: undefined,
configId: undefined,
detailId: undefined,
content: undefined,
viewStatus: undefined,
viewTime: undefined,
params: {}
},
rules: {
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
recipientId: [{ required: true, message: '接收通知的用户ID不能为空', trigger: 'blur' }],
senderId: [{ required: true, message: '发送通知的用户ID不能为空', trigger: 'blur' }],
configId: [{ required: true, message: '配置id不能为空', trigger: 'blur' }],
detailId: [{ required: true, message: '详情id不能为空', trigger: 'blur' }],
content: [{ required: true, message: '通知内容不能为空', trigger: 'blur' }],
viewStatus: [{ required: true, message: '查看状态(0未读 1已读)不能为空', trigger: 'change' }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询消息列表 */
const getList = async () => {
loading.value = true;
const res = await listNotice(queryParams.value);
noticeList.value = res.rows;
if (noticeList.value.length > 0) {
noticeList.value.forEach((item) => {
let obj = JSON.parse(item.content);
item.route = obj.type;
item.msg = obj.content;
});
}
total.value = res.total;
loading.value = false;
};
// 跳转到指定路由
const handleRoute = (row) => {
proxy.$router.push({ path: row.route });
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
noticeFormRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: NoticeVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = '添加消息';
};
/** 修改按钮操作 */
const handleUpdate = async (row?: NoticeVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await getNotice(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改消息';
};
/** 提交按钮 */
const submitForm = () => {
noticeFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateNotice(form.value).finally(() => (buttonLoading.value = false));
} else {
await addNotice(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: NoticeVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除消息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delNotice(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'message/notice/export',
{
...queryParams.value
},
`notice_${new Date().getTime()}.xlsx`
);
};
onMounted(() => {
getList();
});
</script>

View File

@ -1,120 +1,124 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="上报日期" prop="reportDate">
<el-date-picker clearable v-model="queryParams.reportDate" type="date" value-format="YYYY-MM-DD"
placeholder="请选择上报日期" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="上报日期" prop="reportDate">
<el-date-picker clearable v-model="queryParams.reportDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择上报日期" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd"
v-hasPermi="['out:constructionValue:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
v-hasPermi="['out:constructionValue:remove']">删除</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['out:constructionValue:add']">新增</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="constructionValueList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="主键ID" align="center" prop="id" v-if="true" /> -->
<el-table-column label="上报日期" align="center" prop="reportDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.reportDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="项目子项" align="center" prop="subProjectName" />
<el-table-column label="分工程" align="center" prop="categoryName" />
<el-table-column label="分项工程" align="center" prop="progressCategoryName" />
<el-table-column label="人工填报数量" align="center" prop="artificialNum" />
<el-table-column label="无人机识别数量" align="center" prop="uavNum" />
<el-table-column label="确认数量" align="center" prop="confirmNum" />
<el-table-column label="对产值" align="center" prop="outValue" />
<el-table-column label="对甲产值" align="center" prop="ownerValue" />
<el-table-column label="流程状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="wf_business_status" :value="scope.row.auditStatus" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="210">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['out:constructionValue:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['out:constructionValue:remove']">删除</el-button>
<el-button link type="primary" icon="Finished" @click="handleAudit(scope.row)"
v-hasPermi="['out:constructionValue:remove']">审核</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改施工产值对话框 -->
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="constructionValueFormRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="方阵" prop="matrixId" v-if="!form.id">
<el-cascader :options="matrixOptions" placeholder="请选择"
:props="{ value: 'matrixId', label: 'name', emitPath: false }" v-model="form.matrixId"
@clear="resetCascader(1)" @change="handleChange" clearable />
</el-form-item>
<el-form-item label="分项工程" prop="progressCategoryId" v-if="!form.id">
<el-cascader :options="progressCategoryList" v-model="form.progressCategoryId" @clear="resetCascader()"
:disabled="!form.matrixId" @change="selectTime"
:props="{ expandTrigger: 'hover', value: 'id', label: 'name', emitPath: false }" placeholder="请选择分项工程"
clearable>
</el-cascader>
</el-form-item>
<el-form-item label="计划日期" prop="reportDateId" v-if="!form.id">
<el-cascader :options="progressTimeList" v-model="form.reportDateId" :disabled="!form.progressCategoryId"
:props="{ expandTrigger: 'hover', value: 'id', label: 'date', emitPath: false }" placeholder="请选择计划日期"
@change="submitTime" clearable>
</el-cascader>
</el-form-item>
<el-form-item label="人工填报数量" prop="artificialNum">
<el-input v-model="form.artificialNum" placeholder="请输入人工填报数量" disabled />
</el-form-item>
<el-form-item label="无人机识别数量" prop="uavNum">
<el-input v-model="form.uavNum" placeholder="请输入无人机识别数量" disabled />
</el-form-item>
<el-form-item label="上报日期" prop="planDate">
<el-date-picker v-model="form.planDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择上报日期" />
</el-form-item>
<el-form-item label="确认数量" prop="confirmNum">
<el-input v-model="form.confirmNum" placeholder="请输入确认数量" />
</el-form-item>
<!-- <el-form-item label="产值" prop="outValue">
<el-table v-loading="loading" :data="constructionValueList" @selection-change="handleSelectionChange">
<el-table-column type="index" width="55" label="序号" align="center" />
<el-table-column label="上报日期" align="center" prop="reportDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.reportDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="项目子项" align="center" prop="subProjectName" />
<el-table-column label="分部工程" align="center" prop="categoryName" />
<el-table-column label="分工程" align="center" prop="progressCategoryName" />
<el-table-column label="人工填报数量" align="center" prop="artificialNum" />
<el-table-column label="无人机识别数量" align="center" prop="uavNum" />
<el-table-column label="确认数量" align="center" prop="confirmNum" />
<el-table-column label="对乙产值" align="center" prop="outValue" />
<el-table-column label="对产值" align="center" prop="ownerValue" />
<el-table-column label="流程状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="wf_business_status" :value="scope.row.auditStatus" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="210">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['out:constructionValue:edit']">修改</el-button>
<el-button link type="primary" icon="Finished" @click="handleAudit(scope.row)">审核</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改施工产值对话框 -->
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="constructionValueFormRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="方阵" prop="matrixId" v-if="!form.id">
<el-cascader
:options="matrixOptions"
placeholder="请选择"
:props="{ value: 'matrixId', label: 'name', emitPath: false }"
v-model="form.matrixId"
@clear="resetCascader(1)"
@change="handleChange"
clearable
/>
</el-form-item>
<el-form-item label="分项工程" prop="progressCategoryId" v-if="!form.id">
<el-cascader
:options="progressCategoryList"
v-model="form.progressCategoryId"
@clear="resetCascader()"
:disabled="!form.matrixId"
@change="selectTime"
:props="{ expandTrigger: 'hover', value: 'id', label: 'name', emitPath: false }"
placeholder="请选择分项工程"
clearable
>
</el-cascader>
</el-form-item>
<el-form-item label="计划日期" prop="reportDateId" v-if="!form.id">
<el-cascader
:options="progressTimeList"
v-model="form.reportDateId"
:disabled="!form.progressCategoryId"
:props="{ expandTrigger: 'hover', value: 'id', label: 'date', emitPath: false }"
placeholder="请选择计划日期"
@change="submitTime"
clearable
>
</el-cascader>
</el-form-item>
<el-form-item label="人工填报数量" prop="artificialNum">
<el-input v-model="form.artificialNum" placeholder="请输入人工填报数量" disabled />
</el-form-item>
<el-form-item label="无人机识别数量" prop="uavNum">
<el-input v-model="form.uavNum" placeholder="请输入无人机识别数量" disabled />
</el-form-item>
<el-form-item label="上报日期" prop="planDate">
<el-date-picker v-model="form.planDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择上报日期" />
</el-form-item>
<el-form-item label="确认数量" prop="confirmNum">
<el-input v-model="form.confirmNum" placeholder="请输入确认数量" />
</el-form-item>
<!-- <el-form-item label="产值" prop="outValue">
<el-input v-model="form.outValue" disabled />
</el-form-item> -->
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="ConstructionValue" lang="ts">
import {

View File

@ -1,13 +1,11 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="计划月份" prop="planMonth">
<el-date-picker v-model="queryParams.planMonth" type="month" value-format="YYYY-MM"
placeholder="请选择计划月份" />
<el-date-picker v-model="queryParams.planMonth" type="month" value-format="YYYY-MM" placeholder="请选择计划月份" />
</el-form-item>
<el-form-item label="类型" prop="type">
<el-select v-model="queryParams.type" placeholder="请选择类型">
@ -20,18 +18,11 @@
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="monthPlanList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="计划月份" align="center" prop="planMonth" />
<el-table-column label="计划产值" align="center" prop="planValue" />
<el-table-column label="完成产值" align="center" prop="completeValue" />
@ -54,16 +45,15 @@
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="210">
<template #default="scope">
<el-button type="primary" link icon="Edit" @click="handleAdd(scope.row)"
v-hasPermi="['out:monthPlan:add']">编辑</el-button>
<el-button type="primary" link icon="Edit" @click="handleAdd(scope.row)" v-hasPermi="['out:monthPlan:add']">编辑</el-button>
<el-button link type="primary" icon="Finished" @click="handleAudit(scope.row)"
v-hasPermi="['out:constructionValue:remove']">审核</el-button>
<el-button link type="primary" icon="Finished" @click="handleAudit(scope.row)" v-hasPermi="['out:constructionValue:remove']"
>审核</el-button
>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改月度产值计划对话框 -->
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
@ -74,8 +64,14 @@
</el-select>
</el-form-item>
<el-form-item label="计划月份" prop="planMonth">
<el-date-picker v-model="form.planMonth" type="month" value-format="YYYY-MM" disabled placeholder="请选择计划月份"
@change="handlePlanMonthChange" />
<el-date-picker
v-model="form.planMonth"
type="month"
value-format="YYYY-MM"
disabled
placeholder="请选择计划月份"
@change="handlePlanMonthChange"
/>
</el-form-item>
<el-form-item label="计划产值" prop="planValue">
<el-input v-model="form.planValue" placeholder="请输入计划产值" disabled />

View File

@ -1,13 +1,11 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="计划月份" prop="planMonth">
<el-date-picker v-model="queryParams.planMonth" type="month" value-format="YYYY-MM"
placeholder="请选择计划月份" />
<el-date-picker v-model="queryParams.planMonth" type="month" value-format="YYYY-MM" placeholder="请选择计划月份" />
</el-form-item>
<el-form-item label="产值类型" prop="valueType">
<el-select v-model="queryParams.valueType" placeholder="请选择产值类型">
@ -33,19 +31,14 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd"
v-hasPermi="['out:monthPlan:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
v-hasPermi="['out:monthPlan:remove']">删除</el-button>
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['out:monthPlan:add']">新增</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="monthPlanList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table v-loading="loading" :data="monthPlanList">
<el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column label="计划月份" align="center" prop="planMonth" />
<el-table-column label="计划产值" align="center" prop="planValue" />
<el-table-column label="完成产值" align="center" prop="completeValue" />
@ -67,18 +60,15 @@
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope"><el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['out:monthPlan:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['out:monthPlan:remove']">删除</el-button>
<el-button link type="primary" icon="Finished" @click="handleAudit(scope.row)"
v-hasPermi="['out:monthPlan:remove']">审核</el-button>
<template #default="scope"
><el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['out:monthPlan:edit']">修改</el-button>
<!-- <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['out:monthPlan:remove']">删除</el-button> -->
<el-button link type="primary" icon="Finished" @click="handleAudit(scope.row)" v-hasPermi="['out:monthPlan:remove']">审核</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改月度产值计划对话框 -->
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>

View File

@ -2,10 +2,10 @@
<div class="p-2">
<el-tabs type="border-card" @tab-change="handleTabChange" v-model="activeTab">
<el-tab-pane v-for="(item, index) in tabList" :key="index" :label="item.label" :name="item.value">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8"
><el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="计划月份" prop="month">
<el-date-picker v-model="queryParams.month" type="month" value-format="YYYY-MM" placeholder="请选择计划月份" />
</el-form-item>
@ -20,12 +20,6 @@
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>

View File

@ -35,7 +35,7 @@
</el-table>
<el-table v-loading="loading" :data="tableData" v-if="activeTab == '3'">
<el-table-column label="项目" align="center" prop="projectName" />
<el-table-column label="累计完工产值" align="center" prop="totalCompletionOutputValue" />
<!-- <el-table-column label="累计完工产值" align="center" prop="totalCompletionOutputValue" /> -->
<el-table-column label="分包累计结算产值" align="center" prop="subTotalSettlementOutputValue" />
<el-table-column label="业主累计结算产值" align="center" prop="ownerTotalSettlementOutputValue" />
<el-table-column label="差额" align="center" prop="differenceValue" />

View File

@ -1,43 +1,41 @@
<template>
<div class="p-2">
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table height="70vh" v-loading="loading" :data="monthPlanList" @selection-change="handleSelectionChange">
<el-table-column type="index" width="80" label="序号" align="center" />
<el-table-column label="名称" align="center" prop="name" />
<el-table-column label="规格" align="center" prop="specification" />
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="接收数量" align="center" prop="acceptedQuantity" />
<el-table-column label="价格" align="center" prop="unitPrice">
</el-table-column>
<el-table-column label="备注" align="center" prop="remark">
</el-table-column>
<el-table-column label="操作" align="center" prop="remark" v-if="queryParams.type == '1'">
<template #default="scope">
<el-button type="primary" @click="handleUpdate(scope.row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 添加或修改月度产值计划对话框 -->
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="monthPlanFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="金额" prop="unitPrice">
<el-input v-model="form.unitPrice" placeholder="请输入金额" type="number" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
<div class="p-2">
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table height="70vh" v-loading="loading" :data="monthPlanList" @selection-change="handleSelectionChange">
<el-table-column type="index" width="80" label="序号" align="center" />
<el-table-column label="名称" align="center" prop="name" />
<el-table-column label="规格" align="center" prop="specification" />
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="接收数量" align="center" prop="acceptedQuantity" />
<el-table-column label="价格" align="center" prop="unitPrice"> </el-table-column>
<el-table-column label="备注" align="center" prop="remark"> </el-table-column>
<el-table-column label="操作" align="center" prop="remark" v-if="queryParams.type == '1'">
<template #default="scope">
<el-button type="primary" v-hasPermi="['out:monthPlan:purchaseValueAup']" @click="handleUpdate(scope.row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 添加或修改月度产值计划对话框 -->
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="monthPlanFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="金额" prop="unitPrice">
<el-input v-model="form.unitPrice" placeholder="请输入金额" type="number" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="MonthPlan" lang="ts">
@ -59,123 +57,122 @@ const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const monthPlanFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
visible: false,
title: ''
});
const initFormData = {
id: undefined,
id: undefined,
projectId: currentProject.value?.id,
planValue: undefined,
completeValue: undefined,
differenceValue: undefined,
planMonth: undefined,
isDesign: true,
type: '1',
valueType: undefined,
planAuditStatus: undefined,
completeAuditStatus: undefined,
unitPrice: undefined
};
const data = reactive({
form: { ...initFormData },
queryParams: {
projectId: currentProject.value?.id,
planValue: undefined,
completeValue: undefined,
differenceValue: undefined,
planMonth: undefined,
isDesign: true,
type: '1',
valueType: undefined,
planAuditStatus: undefined,
completeAuditStatus: undefined,
unitPrice: undefined,
};
const data = reactive({
form: { ...initFormData },
queryParams: {
projectId: currentProject.value?.id,
planValue: undefined,
completeValue: undefined,
differenceValue: undefined,
planMonth: undefined,
valueType: undefined,
planAuditStatus: undefined,
completeAuditStatus: undefined,
type: '1',
params: {}
},
rules: {
unitPrice: [{ required: true, message: '金额不能为空', trigger: 'change' }]
}
type: '1',
params: {}
},
rules: {
unitPrice: [{ required: true, message: '金额不能为空', trigger: 'change' }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询月度产值计划列表 */
const getList = async (type?) => {
if (type) {
queryParams.value.type = type;
}
loading.value = true;
const res = await purchaseValueA({ projectId: currentProject.value?.id, type: queryParams.value.type });
monthPlanList.value = res.data;
console.log(monthPlanList.value);
if (type) {
queryParams.value.type = type;
}
loading.value = true;
const res = await purchaseValueA({ projectId: currentProject.value?.id, type: queryParams.value.type });
monthPlanList.value = res.data;
console.log(monthPlanList.value);
total.value = res.total;
loading.value = false;
total.value = res.total;
loading.value = false;
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
reset();
dialog.visible = false;
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
monthPlanFormRef.value?.resetFields();
form.value = { ...initFormData };
monthPlanFormRef.value?.resetFields();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: MonthPlanVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 修改按钮操作 */
const handleUpdate = async (row?: MonthPlanVO) => {
reset();
Object.assign(form.value, row);
dialog.visible = true;
dialog.title = '修改采购完工产值';
reset();
Object.assign(form.value, row);
dialog.visible = true;
dialog.title = '修改采购完工产值';
};
/** 提交按钮 */
const submitForm = () => {
form.value.projectId = currentProject.value?.id;
monthPlanFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
form.value.isDesign = true;
if (form.value.id) {
await purchaseValueAup(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
form.value.projectId = currentProject.value?.id;
monthPlanFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
form.value.isDesign = true;
if (form.value.id) {
await purchaseValueAup(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
onMounted(() => {
getList();
getList();
});
//监听项目id刷新数据
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
queryParams.value.projectId = nid;
form.value.projectId = nid;
getList();
}
() => currentProject.value?.id,
(nid, oid) => {
queryParams.value.projectId = nid;
form.value.projectId = nid;
getList();
}
);
onUnmounted(() => {
listeningProject();
listeningProject();
});
defineExpose({
getList
getList
});
</script>

View File

@ -23,7 +23,6 @@ const handleClick = (val) => {
purchPageRef1.value.getList(val.props.name); //子组件方法
} else {
purchPageRef2.value.getList(val.props.name); //子组件方法
}
};
onMounted(() => {

View File

@ -27,17 +27,12 @@
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['out:settlementValueOwner:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['out:settlementValueOwner:remove']"
>删除</el-button
>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="settlementValueOwnerList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="填报人" align="center" prop="createByName" />
<el-table-column label="结算产值" align="center" prop="settlementValue" />
<el-table-column label="产值类型" align="center" prop="valueType">
@ -58,18 +53,12 @@
<el-table-column label="说明" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['out:settlementValueOwner:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
link
type="primary"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['out:settlementValueOwner:remove']"
></el-button>
</el-tooltip>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['out:settlementValueOwner:edit']"
>修改</el-button
>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['out:settlementValueOwner:remove']"
>删除</el-button
>
</template>
</el-table-column>
</el-table>

Some files were not shown because too many files have changed in this diff Show More