Merge branch 'main' of http://xny.yj-3d.com:3000/taoge/mk_system into tcy
This commit is contained in:
@ -6,13 +6,13 @@ VITE_APP_ENV = 'development'
|
||||
|
||||
# 开发环境
|
||||
# 李陈杰 209
|
||||
# VITE_APP_BASE_API = 'http://192.168.110.209:8899'
|
||||
VITE_APP_BASE_API = 'http://192.168.110.180:8899'
|
||||
# 曾涛
|
||||
# VITE_APP_BASE_API = 'http://192.168.110.180: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.149:8899'
|
||||
#曾涛
|
||||
# VITE_APP_BASE_API = 'http://192.168.110.171:8899'
|
||||
|
||||
|
Binary file not shown.
@ -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>
|
||||
|
@ -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
|
||||
});
|
||||
};
|
||||
|
@ -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'
|
||||
});
|
||||
};
|
||||
|
@ -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
|
||||
});
|
||||
};
|
||||
|
@ -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
|
||||
});
|
||||
};
|
||||
|
@ -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'
|
||||
});
|
||||
};
|
||||
|
@ -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'
|
||||
});
|
||||
}
|
||||
|
@ -54,6 +54,14 @@ export interface ContractorForm extends BaseEntity {
|
||||
* 主键id
|
||||
*/
|
||||
id?: string | number;
|
||||
/**
|
||||
* 供应商id
|
||||
*/
|
||||
supplierId?: string | number;
|
||||
/**
|
||||
* 供应商
|
||||
*/
|
||||
supplier?: string;
|
||||
|
||||
/**
|
||||
* 主键id
|
||||
|
@ -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'
|
||||
});
|
||||
};
|
||||
|
@ -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',
|
||||
|
@ -68,3 +68,11 @@ export const delMenu = (menuId: string | number) => {
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
// 获取所有路由
|
||||
export const getAllRouters = () => {
|
||||
return request({
|
||||
url: '/system/menu/getAllRouters',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
@ -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'
|
||||
});
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 = {
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 (['/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') {
|
||||
next({ path: '/' });
|
||||
NProgress.done();
|
||||
} else if (isWhiteList(to.path)) {
|
||||
next();
|
||||
} else {
|
||||
if (useUserStore().roles.length === 0) {
|
||||
return { path: '/' };
|
||||
}
|
||||
|
||||
if (isWhiteList(to.path)) {
|
||||
return true;
|
||||
}
|
||||
if ((!isFirst && useUserStore().roles.length === 0) || $cache.local.getJSON('isCheckRole') === 'true') {
|
||||
isFirst = true;
|
||||
isRelogin.show = true;
|
||||
// 判断当前用户是否已拉取完user_info信息
|
||||
|
||||
const [err] = await tos(useUserStore().getInfo());
|
||||
|
||||
if (err) {
|
||||
await useUserStore().logout();
|
||||
ElMessage.error(err);
|
||||
next({ path: '/' });
|
||||
} else {
|
||||
NProgress.done();
|
||||
return { path: '/' };
|
||||
}
|
||||
|
||||
isRelogin.show = false;
|
||||
const accessRoutes = await usePermissionStore().generateRoutes();
|
||||
// 根据roles权限生成可访问的路由表
|
||||
accessRoutes.forEach((route) => {
|
||||
if (!isHttp(route.path)) {
|
||||
router.addRoute(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已完成
|
||||
|
||||
$cache.local.remove('isCheckRole');
|
||||
|
||||
// 确保路由已添加后再跳转
|
||||
return { ...to, replace: true };
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
next();
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 没有token
|
||||
|
||||
// 未登录
|
||||
if (isWhiteList(to.path)) {
|
||||
// 在免登录白名单,直接进入
|
||||
next();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
const redirect = encodeURIComponent(to.fullPath || '/');
|
||||
next(`/login?redirect=${redirect}`); // 否则全部重定向到登录页
|
||||
NProgress.done();
|
||||
}
|
||||
}
|
||||
return { path: `/login?redirect=${redirect}` };
|
||||
});
|
||||
|
||||
router.afterEach(() => {
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -20,12 +20,10 @@ export const initSSE = (url: any) => {
|
||||
});
|
||||
|
||||
watch(error, () => {
|
||||
console.log('SSE connection error:', error.value);
|
||||
error.value = null;
|
||||
});
|
||||
|
||||
watch(data, () => {
|
||||
console.log('🚀 ~ initSSE ~ data:', JSON.parse(data.value));
|
||||
let label = '';
|
||||
let route1 = '';
|
||||
let detailId = '';
|
||||
@ -33,6 +31,9 @@ export const initSSE = (url: any) => {
|
||||
if (JSON.parse(data.value)) {
|
||||
const obj = JSON.parse(data.value);
|
||||
route1 = obj.type;
|
||||
if (obj.type == 'count') {
|
||||
return;
|
||||
}
|
||||
label = obj.content;
|
||||
// detailId = obj.detailId;
|
||||
data.value = null;
|
||||
|
@ -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">
|
||||
|
@ -48,7 +48,7 @@
|
||||
icon="view"
|
||||
@click="handleViewInfo"
|
||||
v-hasPermi="['bidding:biddingLimitList:getVersionDetail']"
|
||||
v-if="versionObj.status != 'draft'"
|
||||
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"
|
||||
@ -85,7 +94,7 @@
|
||||
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
|
||||
@ -187,18 +196,21 @@ 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'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (type == 'single') {
|
||||
loading.value = true;
|
||||
biddingLimitListUpdate(row).then((res) => {
|
||||
const list = [{ ...row }];
|
||||
biddingLimitListUpdate(list).then((res) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage({
|
||||
message: '修改成功',
|
||||
@ -207,11 +219,30 @@ const handleSave = (row: any) => {
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage({
|
||||
message: '修改失败',
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
const tableRef = ref<any>();
|
||||
|
@ -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>
|
||||
|
@ -35,14 +35,15 @@
|
||||
<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="warning"
|
||||
icon="view"
|
||||
v-if="reviewStatus != 'draft'"
|
||||
v-if="reviewStatus && reviewStatus != 'draft'"
|
||||
@click="clickApprovalSheet()"
|
||||
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
||||
>查看流程</el-button
|
||||
@ -56,7 +57,11 @@
|
||||
<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
|
||||
@ -65,6 +70,7 @@
|
||||
@change="
|
||||
(val) => {
|
||||
scope.row.unitPrice = val;
|
||||
changePrice(scope.row);
|
||||
}
|
||||
"
|
||||
:precision="2"
|
||||
@ -87,7 +93,7 @@
|
||||
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
|
||||
@ -220,18 +226,18 @@ 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'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (type == 'single') {
|
||||
loading.value = true;
|
||||
updatePrice({ ...row, type: '1' }).then((res) => {
|
||||
const list = [{ ...row, type: '1' }];
|
||||
updatePrice(list).then((res) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage({
|
||||
message: '修改成功',
|
||||
@ -240,11 +246,30 @@ const handleSave = (row: any) => {
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage({
|
||||
message: '修改失败',
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
const tableRef = ref<any>();
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
/** 回显表单数据(编辑/查看/审批场景) */
|
||||
|
804
src/views/design/appointment/index copy 2.vue
Normal file
804
src/views/design/appointment/index copy 2.vue
Normal 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
@ -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,8 +83,31 @@
|
||||
@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"
|
||||
@ -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({
|
||||
|
@ -36,7 +36,7 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工程名称" prop="projectName">
|
||||
<el-input v-model="form.projectName" placeholder="请输入工程名称" /> </el-form-item
|
||||
<el-input v-model="form.projectName" disabled placeholder="请输入工程名称" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="原卷册号" prop="volumeNo">
|
||||
@ -145,7 +145,7 @@
|
||||
></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-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">
|
||||
@ -254,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,
|
||||
@ -348,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(',');
|
||||
}
|
||||
@ -374,7 +377,6 @@ 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;
|
||||
@ -392,6 +394,9 @@ const submitForm = (status1: string) => {
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
submit(status.value, form.value);
|
||||
}
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
@ -429,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('暂存成功');
|
||||
|
@ -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 () => {
|
||||
// 判断是否还需要设计验证
|
||||
if (form.value.isWindow) {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
|
||||
// submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
} 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;
|
||||
|
@ -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 id:designer
|
||||
// 校审人员 名称 proofreading id: proofreadingId 校审时间 proofreadingDate
|
||||
// 审定人员 名称 approve id:approveId 审定时间 approveDate
|
||||
// 审核人员 名称 audit id:auditId 审核时间 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>
|
||||
|
||||
|
@ -434,7 +434,7 @@ const onLoad = async () => {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
proxy?.download('design/collect/exportWord', { id: form.id }, `收资清单_${new Date().getTime()}.zip`);
|
||||
proxy?.download('design/collect/exportWord', { id: form.id }, `收资清单_${new Date().getTime()}.doc`);
|
||||
} catch (error) {
|
||||
ElMessage.error('导出失败,请重试');
|
||||
console.error('文件导出错误:', error);
|
||||
|
@ -39,7 +39,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
|
||||
@ -202,8 +202,14 @@ const submitCallback = async () => {
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
// 图纸评审验证
|
||||
// 图纸评审验证 判断是否需要设计验证
|
||||
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;
|
||||
|
@ -55,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>
|
||||
@ -539,7 +541,6 @@ const onSubmit = async () => {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: VolumeCatalogVO) => {
|
||||
const _ids = row?.design || ids.value;
|
||||
|
@ -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;
|
||||
|
@ -48,6 +48,20 @@
|
||||
<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
|
||||
@ -67,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>
|
||||
@ -230,6 +244,11 @@
|
||||
}
|
||||
}"
|
||||
/>
|
||||
<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>
|
||||
@ -238,6 +257,27 @@
|
||||
</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>
|
||||
|
||||
@ -253,12 +293,15 @@ import {
|
||||
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
|
||||
@ -287,6 +330,7 @@ const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const file = ref(null);
|
||||
const fileParams = reactive({
|
||||
pageNum: 1,
|
||||
@ -404,7 +448,39 @@ const handleAdd = async () => {
|
||||
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];
|
||||
|
@ -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]">
|
||||
|
@ -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;
|
||||
|
@ -6,8 +6,8 @@
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5" :offset="0"
|
||||
><el-button
|
||||
<el-col :span="1.5" :offset="0">
|
||||
<el-button
|
||||
type="primary"
|
||||
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:add']"
|
||||
size="default"
|
||||
@ -15,10 +15,10 @@
|
||||
icon="FolderAdd"
|
||||
plain
|
||||
>新增</el-button
|
||||
></el-col
|
||||
>
|
||||
<el-col :span="1.5" :offset="0"
|
||||
><el-button
|
||||
</el-col>
|
||||
<el-col :span="1.5" :offset="0">
|
||||
<el-button
|
||||
type="danger"
|
||||
size="default"
|
||||
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:remove']"
|
||||
@ -27,8 +27,8 @@
|
||||
icon="FolderDelete"
|
||||
plain
|
||||
>删除</el-button
|
||||
></el-col
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
@ -70,19 +70,17 @@
|
||||
>修改</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" />
|
||||
@ -103,7 +101,7 @@
|
||||
</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">
|
||||
@ -125,63 +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-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-input v-model="scope.row.name" v-if="scope.row.mrpBaseId" placeholder="请输入物资名称" disabled />
|
||||
<el-select
|
||||
:disabled="!scope.row.versions"
|
||||
v-else
|
||||
:disabled="!scope.row.batchNumber"
|
||||
v-model="scope.row.suppliespriceId"
|
||||
placeholder="请选择"
|
||||
@change="(val) => selectName(val, scope.row)"
|
||||
@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">
|
||||
<template #header> <span class="text-red">*</span> 质量标准 </template>
|
||||
<!-- 数量列(新增错误提示展示) -->
|
||||
<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="需求到货时间">
|
||||
<template #header> <span class="text-red">*</span> 需求到货时间 </template>
|
||||
|
||||
<!-- 需求到货时间列 -->
|
||||
<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" />
|
||||
</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>
|
||||
@ -206,10 +234,48 @@ import {
|
||||
listSelectCailiaoshebei,
|
||||
obtainTheVersion,
|
||||
getDictList,
|
||||
coryEngineeringList
|
||||
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
|
||||
@ -227,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,
|
||||
@ -246,7 +312,6 @@ const initFormData: any = {
|
||||
status: undefined,
|
||||
projectId: currentProject.value?.id
|
||||
},
|
||||
|
||||
planList: [
|
||||
{
|
||||
id: undefined,
|
||||
@ -257,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: {
|
||||
@ -285,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;
|
||||
try {
|
||||
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;
|
||||
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;
|
||||
total.value = res.total || 0;
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('获取批次列表失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
if (type === 'search') return;
|
||||
// 非搜索场景下同步加载主列表
|
||||
if (type !== 'search') {
|
||||
getMainList();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const selectName = (val: any, row: any) => {
|
||||
const selected = nameList.value.find((item) => item.id === val);
|
||||
/** 数量校验:必须≤剩余量,且为合法数字 */
|
||||
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.demandQuantity = selected.quantity;
|
||||
row.remark = selected.remark;
|
||||
row.arrivalTime = selected.arrivalTime;
|
||||
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;
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await getBatch(queryParams.value.mainData);
|
||||
cailiaoshebeiList.value = res.rows;
|
||||
mainTotal.value = res.total;
|
||||
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);
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
@ -367,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;
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
@ -411,93 +572,157 @@ 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);
|
||||
});
|
||||
// 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);
|
||||
if (!result.valid) {
|
||||
proxy?.$modal.msgError(result.message);
|
||||
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) {
|
||||
if (!valid) return;
|
||||
|
||||
buttonLoading.value = true;
|
||||
form.value.planList = result.data;
|
||||
await updateCailiaoshebei(form.value).finally(() => (buttonLoading.value = false));
|
||||
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);
|
||||
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('删除失败');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
interface ValidateResult {
|
||||
valid: boolean;
|
||||
data: any[];
|
||||
errors: { index: number; field: string; message: string }[];
|
||||
}
|
||||
/** 数据清洗与基础校验 */
|
||||
function validateAndClean(arr: PlanListItem[]) {
|
||||
// 1. 过滤掉全空的数据项
|
||||
const cleanedArr = arr.filter((item) => !Object.values(item).every((v) => v === '' || v == null || v === undefined));
|
||||
|
||||
function validateAndClean(arr: any[]) {
|
||||
// 过滤掉全空的数据项
|
||||
const cleanedArr = arr.filter((item) => !Object.values(item).every((v) => v === '' || v == null));
|
||||
|
||||
let hasFullItem = false; // 是否有至少一条全填数据
|
||||
let hasFullItem = false; // 是否有至少一条完整数据
|
||||
|
||||
// 2. 逐行校验必填项
|
||||
for (let idx = 0; idx < cleanedArr.length; idx++) {
|
||||
const item = cleanedArr[idx];
|
||||
const keys = Object.keys(item).filter((k) => k !== 'remark' && k !== 'id');
|
||||
|
||||
const allFilled = keys.every((k) => item[k] !== '' && item[k] != null);
|
||||
const allEmpty = Object.values(item).every((v) => v === '' || v == null);
|
||||
// 校验版本号
|
||||
if (!item.batchNumber) {
|
||||
return { valid: false, message: `第${idx + 1}行:版本号不能为空`, data: cleanedArr };
|
||||
}
|
||||
|
||||
// 单独检查 qs 和 arrivalTime
|
||||
// 校验物资选择
|
||||
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 };
|
||||
}
|
||||
|
||||
// 检查其他字段是否部分填
|
||||
if (!allFilled && !allEmpty) {
|
||||
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 };
|
||||
}
|
||||
|
||||
if (allFilled) {
|
||||
hasFullItem = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否至少有一条完整的数据
|
||||
// 3. 检查是否至少有一条完整数据
|
||||
if (!hasFullItem) {
|
||||
return { valid: false, message: '至少需要一条完整的数据', data: cleanedArr };
|
||||
return { valid: false, message: '至少需要填写一条完整的物资数据', data: cleanedArr };
|
||||
}
|
||||
|
||||
return { valid: true, message: '', data: cleanedArr };
|
||||
@ -506,54 +731,96 @@ function validateAndClean(arr: any[]) {
|
||||
/** 审核按钮操作 */
|
||||
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 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) => {
|
||||
versionList.value = res.data;
|
||||
});
|
||||
};
|
||||
const selectNameVersion = (val, row) => {
|
||||
row.suppliespriceId = undefined;
|
||||
getNameList(val);
|
||||
};
|
||||
|
||||
/** 获取版本号列表 */
|
||||
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;
|
||||
(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;
|
||||
@ -563,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>
|
||||
|
@ -56,7 +56,7 @@
|
||||
<el-table-column label="操作" align="center" min-width="150" fixed="right">
|
||||
<template #default="scope">
|
||||
<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="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
|
||||
>
|
||||
@ -85,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">
|
||||
@ -129,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>
|
||||
@ -140,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">
|
||||
@ -149,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>
|
||||
@ -242,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();
|
||||
@ -265,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,
|
||||
@ -279,7 +296,7 @@ const getInitFormData = () => {
|
||||
materialSource: '1',
|
||||
formCode: undefined,
|
||||
projectName: undefined,
|
||||
materialName: undefined,
|
||||
materialName: '', // 初始化为空字符串
|
||||
orderingUnit: undefined,
|
||||
supplierUnit: undefined,
|
||||
issueUnit: undefined,
|
||||
@ -302,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,
|
||||
@ -326,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;
|
||||
try {
|
||||
const res = await listMaterialIssue(queryParams.value);
|
||||
materialIssueList.value = res.rows;
|
||||
total.value = res.total;
|
||||
} finally {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取材料名称列表
|
||||
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`);
|
||||
}
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
@ -373,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;
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
@ -401,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];
|
||||
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('获取详情失败');
|
||||
}
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
@ -418,21 +593,38 @@ const submitForm = () => {
|
||||
materialIssueFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
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(form.value).finally(() => (buttonLoading.value = false));
|
||||
await updateMaterialIssue(submitData);
|
||||
} else {
|
||||
await addMaterialIssue(form.value).finally(() => (buttonLoading.value = false));
|
||||
await addMaterialIssue(submitData);
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('操作失败');
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 添加数量验收条目
|
||||
const addItem = () => {
|
||||
form.value.itemList.push({
|
||||
const newItem = {
|
||||
id: undefined,
|
||||
specification: undefined,
|
||||
unit: undefined,
|
||||
@ -440,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));
|
||||
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">
|
||||
|
@ -57,16 +57,15 @@
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<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="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-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>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -74,7 +73,15 @@
|
||||
</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">
|
||||
@ -122,7 +129,6 @@
|
||||
:value="item.contractCode"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<!-- <el-input v-model="form.contractName" placeholder="请输入合同名称" /> -->
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
@ -131,14 +137,13 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 数量验收区域(修复v-for key问题) -->
|
||||
<!-- 数量验收区域 -->
|
||||
<el-col :span="24">
|
||||
<div class="detail">
|
||||
<div class="detail-header">
|
||||
<span>数量验收</span>
|
||||
<el-button type="primary" v-if="form.materialSource == '1'" link @click="addItem" icon="Plus">添加数量验收</el-button>
|
||||
</div>
|
||||
<!-- 关键修复:v-for key改为item.id(唯一标识),而非index -->
|
||||
<div v-for="(item, index) in form.itemList" :key="item.id" class="detail-item">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
@ -161,21 +166,27 @@
|
||||
</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="form.materialSource == '2'" 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">
|
||||
@ -184,13 +195,13 @@
|
||||
:prop="`itemList.${index}.shortageQuantity`"
|
||||
:rules="{ required: true, message: '缺件数量不能为空', trigger: 'blur' }"
|
||||
>
|
||||
<el-input type="number" v-model="item.shortageQuantity" placeholder="自动计算(数量-验收数量)" readonly />
|
||||
<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-col :span="24">
|
||||
<el-form-item label="备注" :prop="`itemList.${index}.remark`">
|
||||
<el-input v-model="item.remark" placeholder="请输入备注" />
|
||||
<el-input v-model="item.remark" type="textarea" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.itemList.length > 1 && form.materialSource == '1'">
|
||||
@ -205,26 +216,26 @@
|
||||
|
||||
<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="remark">
|
||||
@ -258,7 +269,7 @@ import { useUserStoreHook } from '@/store/modules/user';
|
||||
import wordllReceive from './word/index.vue';
|
||||
import { listPurchaseDoc, purchaseDocPlanList } from '@/api/materials/purchaseDoc';
|
||||
import { watch, onMounted, onUnmounted, ref, reactive, computed, toRefs, getCurrentInstance } from 'vue';
|
||||
import type { ComponentInternalInstance, ElFormInstance, DialogOption } from 'element-plus';
|
||||
import type { ComponentInternalInstance, ElFormInstance, DialogOption, ElFormItem } from 'element-plus';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { storage_type } = toRefs<any>(proxy?.useDict('storage_type'));
|
||||
@ -266,8 +277,10 @@ const userStore = useUserStoreHook();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const wordllReceiveRef = ref<InstanceType<typeof wordllReceive>>();
|
||||
|
||||
// 核心修复1:存储每个验收条目的watch停止函数,避免内存泄漏
|
||||
// 存储每个验收条目的watch停止函数
|
||||
const itemWatchStopFns = ref<Array<() => void>>([]);
|
||||
// 存储数量表单项的引用,用于手动触发验证
|
||||
const quantityFormItemRefs = ref<(ElFormItem | null)[]>([]);
|
||||
|
||||
// 列表数据
|
||||
const materialReceiveList = ref<MaterialReceiveVO[]>([]);
|
||||
@ -285,18 +298,19 @@ const materialReceiveFormRef = ref<ElFormInstance>();
|
||||
const purchaseDocList = ref([]); // 物资采购单列表
|
||||
const purchaseMap = new Map(); // 采购单映射(id -> 采购单对象)
|
||||
const contractNameList = ref([]); //合同列表
|
||||
|
||||
// 对话框配置
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
// 生成验收条目唯一ID(用于v-for key)
|
||||
// 生成验收条目唯一ID
|
||||
const generateItemId = () => {
|
||||
return Date.now() + Math.random().toString(36).substr(2, 9);
|
||||
};
|
||||
|
||||
// 初始化表单数据(修复:给验收条目添加唯一ID)
|
||||
// 初始化表单数据
|
||||
const getInitFormData = (): MaterialReceiveForm => {
|
||||
return {
|
||||
id: undefined,
|
||||
@ -323,7 +337,7 @@ const getInitFormData = (): MaterialReceiveForm => {
|
||||
docCode: undefined,
|
||||
itemList: [
|
||||
{
|
||||
id: generateItemId(), // 新增:唯一ID,解决v-for渲染问题
|
||||
id: generateItemId(),
|
||||
name: undefined,
|
||||
specification: undefined,
|
||||
unit: undefined,
|
||||
@ -357,7 +371,38 @@ const data = reactive({
|
||||
formCode: [{ 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']
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
@ -374,25 +419,29 @@ const getList = async () => {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取合同列表数据
|
||||
const getContractList = async () => {
|
||||
let res = await getContractNameList(currentProject.value?.id);
|
||||
contractNameList.value = res.rows;
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
};
|
||||
|
||||
/** 表单重置(修复:清理验收条目监听) */
|
||||
/** 表单重置 */
|
||||
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) {
|
||||
@ -408,7 +457,9 @@ const handleQuery = () => {
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
if (queryFormRef.value) {
|
||||
queryFormRef.value.resetFields();
|
||||
}
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
@ -427,24 +478,35 @@ const handleAdd = () => {
|
||||
form.value.projectName = currentProject.value?.name;
|
||||
};
|
||||
|
||||
/** 修改按钮操作(修复:清理旧监听+添加唯一ID) */
|
||||
/** 修改按钮操作(核心修复:赋值后主动触发验证+数据类型转换) */
|
||||
const handleUpdate = async (row?: MaterialReceiveVO) => {
|
||||
reset();
|
||||
const _id = row?.id || ids.value[0];
|
||||
|
||||
try {
|
||||
const res = await getMaterialReceive(_id);
|
||||
// 给验收条目补充唯一ID(避免后端返回无ID)
|
||||
const formData = res.data;
|
||||
|
||||
// 修复1:处理itemList数据类型,确保数量/验收数量为数字(避免字符串与number规则冲突)
|
||||
formData.itemList = formData.itemList.map((item) => ({
|
||||
...item,
|
||||
id: item.id || generateItemId()
|
||||
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;
|
||||
@ -460,13 +522,24 @@ const submitForm = () => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
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({ ...form.value });
|
||||
await updateMaterialReceive(submitForm);
|
||||
} else {
|
||||
form.value.itemList.forEach((item) => {
|
||||
submitForm.itemList.forEach((item) => {
|
||||
delete item.id;
|
||||
});
|
||||
await addMaterialReceive({ ...form.value });
|
||||
await addMaterialReceive(submitForm);
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
@ -495,10 +568,10 @@ const handleDelete = async (row?: MaterialReceiveVO) => {
|
||||
}
|
||||
};
|
||||
|
||||
/** 添加数量验收条目(修复:添加唯一ID+监听) */
|
||||
/** 添加数量验收条目 */
|
||||
const addItem = () => {
|
||||
const newItem = {
|
||||
id: generateItemId(), // 唯一ID
|
||||
id: generateItemId(),
|
||||
name: undefined,
|
||||
specification: undefined,
|
||||
unit: undefined,
|
||||
@ -508,33 +581,79 @@ const addItem = () => {
|
||||
remark: undefined
|
||||
};
|
||||
form.value.itemList.push(newItem);
|
||||
// 监听新条目变化
|
||||
// 监听新条目变化并触发初始验证
|
||||
watchItemChanges(form.value.itemList.length - 1);
|
||||
validateQuantityField(form.value.itemList.length - 1);
|
||||
};
|
||||
|
||||
/** 监听验收条目变化,自动计算缺件数量(修复:存储停止函数) */
|
||||
// 数量输入事件处理
|
||||
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 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 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;
|
||||
const acceptedQty = Number(acceptedQuantity) || 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 } // 初始时立即计算
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 存储停止函数,用于后续删除时清理
|
||||
itemWatchStopFns.value[index] = stopFn;
|
||||
};
|
||||
|
||||
/** 删除数量验收条目(修复:清理监听+删除条目) */
|
||||
/** 删除数量验收条目 */
|
||||
const removeItem = (index: number) => {
|
||||
if (form.value.itemList.length <= 1) {
|
||||
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
|
||||
@ -549,6 +668,7 @@ const removeItem = (index: number) => {
|
||||
// 删除条目和对应的停止函数
|
||||
form.value.itemList.splice(index, 1);
|
||||
itemWatchStopFns.value.splice(index, 1);
|
||||
quantityFormItemRefs.value.splice(index, 1);
|
||||
};
|
||||
|
||||
/** 查看详情 */
|
||||
@ -564,7 +684,6 @@ const getlistPurchase = async () => {
|
||||
status: 'finish'
|
||||
});
|
||||
purchaseDocList.value = res.rows;
|
||||
// 构建采购单映射
|
||||
purchaseDocList.value.forEach((item) => {
|
||||
purchaseMap.set(item.id, item);
|
||||
});
|
||||
@ -573,7 +692,7 @@ const getlistPurchase = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
/** 通过采购单获取需求信息(修复:清理旧监听+添加新监听) */
|
||||
/** 通过采购单获取需求信息(修复:数据类型转换) */
|
||||
const getdemandInfo = async (docId: string) => {
|
||||
if (!docId) return;
|
||||
|
||||
@ -583,25 +702,25 @@ const getdemandInfo = async (docId: string) => {
|
||||
// 清空旧监听和条目
|
||||
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(), // 唯一ID
|
||||
id: generateItemId(),
|
||||
name: item.name,
|
||||
specification: item.specification,
|
||||
unit: item.unit,
|
||||
quantity: qty,
|
||||
acceptedQuantity: 0,
|
||||
shortageQuantity: qty, // 初始缺件=总数量
|
||||
quantity: qty, // 确保数字类型
|
||||
acceptedQuantity: 0, // 初始值为0(数字)
|
||||
shortageQuantity: qty, // 初始缺件=数量(数字)
|
||||
remark: item.remark,
|
||||
planId: item.id,
|
||||
id: null // 保留后端需要的空id字段
|
||||
id: null
|
||||
};
|
||||
form.value.itemList.push(newItem);
|
||||
// 监听当前条目
|
||||
watchItemChanges(index);
|
||||
});
|
||||
}
|
||||
@ -621,21 +740,25 @@ const handleSelect = (val: string) => {
|
||||
form.value.materialName = obj.name || '';
|
||||
}
|
||||
|
||||
// 获取采购单对应的需求信息
|
||||
getdemandInfo(val);
|
||||
};
|
||||
|
||||
/** 核心修复2:监听材料来源变化,重置数量验收列表 */
|
||||
/** 监听材料来源变化,重置数量验收列表 */
|
||||
watch(
|
||||
() => form.value.materialSource,
|
||||
(newSource, oldSource) => {
|
||||
if (newSource === oldSource) return;
|
||||
|
||||
// 1. 停止所有验收条目的监听
|
||||
// 停止所有验收条目的监听
|
||||
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
||||
itemWatchStopFns.value = [];
|
||||
|
||||
// 2. 重置数量验收列表为初始状态(1条空记录)
|
||||
quantityFormItemRefs.value = [];
|
||||
// 清空所有文件上传字段的值
|
||||
form.value.certCountFileId = undefined; // 合格证文件
|
||||
form.value.reportCountFileId = undefined; // 出厂报告文件
|
||||
form.value.techDocCountFileId = undefined; // 技术资料文件
|
||||
form.value.licenseCountFileId = undefined; // 厂家资质文件
|
||||
// 重置数量验收列表为初始状态
|
||||
form.value.itemList = [
|
||||
{
|
||||
id: generateItemId(),
|
||||
@ -649,10 +772,11 @@ watch(
|
||||
}
|
||||
];
|
||||
|
||||
// 3. 重新监听初始条目
|
||||
// 重新监听初始条目并触发验证
|
||||
watchItemChanges(0);
|
||||
validateQuantityField(0);
|
||||
|
||||
// 4. 切换到乙供时,清空采购单相关数据
|
||||
// 切换到乙供时,清空采购单相关数据
|
||||
if (newSource === '2') {
|
||||
form.value.docId = undefined;
|
||||
form.value.supplierUnit = undefined;
|
||||
@ -668,9 +792,10 @@ onMounted(() => {
|
||||
getContractList();
|
||||
getList();
|
||||
getlistPurchase();
|
||||
// 监听初始验收条目
|
||||
// 监听初始验收条目并触发验证
|
||||
if (form.value.itemList.length > 0) {
|
||||
watchItemChanges(0);
|
||||
validateQuantityField(0);
|
||||
}
|
||||
});
|
||||
|
||||
@ -689,7 +814,6 @@ const listeningProject = watch(
|
||||
/** 页面卸载时清理监听 */
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
// 清理验收条目监听
|
||||
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
||||
});
|
||||
</script>
|
||||
|
@ -116,6 +116,9 @@
|
||||
<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>
|
||||
@ -130,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"
|
||||
@ -265,6 +268,7 @@ 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();
|
||||
@ -304,6 +308,8 @@ const initFormData: any = {
|
||||
docCode: undefined,
|
||||
supplier: undefined,
|
||||
reason: undefined,
|
||||
supplierId: undefined,
|
||||
|
||||
name: undefined,
|
||||
arrivalDate: undefined,
|
||||
designDirectorTel: undefined,
|
||||
@ -379,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('加载中');
|
||||
@ -467,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));
|
||||
@ -502,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;
|
||||
|
@ -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" />
|
||||
|
@ -23,9 +23,9 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['patch:master:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<!-- <el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['patch:master:export']">导出</el-button>
|
||||
</el-col>
|
||||
</el-col> -->
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
@ -64,32 +64,32 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="计量单位" align="center" prop="unit">
|
||||
<template #default="{ row }">
|
||||
{{ row.parentId == 0 ? '' : row.unit }}
|
||||
{{ row.unitType == 0 ? '' : row.unit }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="综合单价(业主)" align="center" prop="ownerPrice">
|
||||
<template #default="{ row }">
|
||||
{{ row.parentId == 0 ? '' : row.ownerPrice }}
|
||||
{{ row.unitType == 0 ? '' : row.ownerPrice }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="综合单价(分包)" align="center" prop="constructionPrice">
|
||||
<template #default="{ row }">
|
||||
{{ row.parentId == 0 ? '' : row.constructionPrice }}
|
||||
{{ row.unitType == 0 ? '' : row.constructionPrice }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="产值金额(业主)" align="center" prop="ownerOutputValue">
|
||||
<template #default="{ row }">
|
||||
{{ row.parentId == 0 ? '' : row.ownerOutputValue }}
|
||||
{{ row.unitType == 0 ? '' : row.ownerOutputValue }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="产值金额(分包)" align="center" prop="constructionOutputValue">
|
||||
<template #default="{ row }">
|
||||
{{ row.parentId == 0 ? '' : row.constructionOutputValue }}
|
||||
{{ row.unitType == 0 ? '' : row.constructionOutputValue }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总数量" align="center" prop="total">
|
||||
<template #default="{ row }">
|
||||
{{ row.parentId == 0 ? '' : row.total }}
|
||||
{{ row.unitType == 0 ? '' : row.total }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关联结构" align="center" prop="relevancyStructure" width="100">
|
||||
@ -128,7 +128,7 @@
|
||||
check-strictly
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="计量方式" prop="unitType" v-if="!form.workType">
|
||||
<el-form-item label="计量方式" prop="unitType" v-if="!form.workType && form.unitType != '0'">
|
||||
<el-select v-model="form.unitType" placeholder="请选择关联数据">
|
||||
<el-option v-for="dict in progress_unit_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
@ -153,12 +153,12 @@
|
||||
<el-option v-for="dict in progress_work_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关联结构" prop="relevancyStructure">
|
||||
<!-- <el-form-item label="关联结构" prop="relevancyStructure">
|
||||
<el-select v-model="form.relevancyStructure" value-key="" placeholder="请选择关联结构" clearable filterable @change="">
|
||||
<el-option label="子项目" value="1"></el-option>
|
||||
<el-option label="方阵" value="2"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="备注" prop="remark" v-if="!form.id">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
@ -433,12 +433,12 @@ const handleUpdate = async (row: ProgressCategoryVO) => {
|
||||
};
|
||||
|
||||
const handleExport = async () => {
|
||||
const ids = treeRef.value.getCheckedNodes()[0].pathNodes[0].childrenData.map((item) => item.matrixId);
|
||||
const fileName = treeRef.value.getCheckedNodes()[0].pathNodes[0].label;
|
||||
const ids = queryParams.value.projectId;
|
||||
const fileName = matrixOptions.value.find((item) => item.projectId == ids)?.name || currentProject.value?.name || '工程项目';
|
||||
proxy?.download(
|
||||
'/progress/progressCategory/export',
|
||||
{
|
||||
ids: ids
|
||||
projectId: ids
|
||||
},
|
||||
`${fileName}分项工程单价导入.xlsx`,
|
||||
true
|
||||
|
@ -81,6 +81,11 @@
|
||||
<el-form-item label="公司名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入公司名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="供应商" prop="supplier">
|
||||
<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-form-item label="负责人" prop="principal">
|
||||
<el-input v-model="form.principal" placeholder="请输入负责人" />
|
||||
</el-form-item>
|
||||
@ -121,6 +126,7 @@ import { ContractorForm, ContractorQuery, ContractorVO } from '@/api/project/con
|
||||
import ContractorFileDialog from '@/views/project/contractor/component/ContractorFileDialog.vue';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { getDicts, listData } from '@/api/system/dict/data';
|
||||
import { listSupplierInput } from '@/api/supplierInput/supplierInput';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@ -152,6 +158,8 @@ const initFormData: ContractorForm = {
|
||||
principalPhone: undefined,
|
||||
custodian: undefined,
|
||||
custodianPhone: undefined,
|
||||
supplierId: undefined,
|
||||
supplier: undefined,
|
||||
contractorType: undefined,
|
||||
fileMap: undefined,
|
||||
remark: undefined,
|
||||
@ -257,6 +265,8 @@ const submitForm = () => {
|
||||
if (valid) {
|
||||
form.value.projectId = currentProject.value?.id;
|
||||
buttonLoading.value = true;
|
||||
form.value.supplier = supplierOptions.value.find((item) => item.id == form.value.supplierId)?.supplierName;
|
||||
|
||||
if (form.value.id) {
|
||||
await updateContractor(form.value).finally(() => (buttonLoading.value = false));
|
||||
} else {
|
||||
@ -278,15 +288,16 @@ const handleDelete = async (row?: ContractorVO) => {
|
||||
await getList();
|
||||
};
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download(
|
||||
'project/contractor/export',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`contractor_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
/** 获取供应商 */
|
||||
const supplierOptions = ref([]);
|
||||
const getSupplierList = async () => {
|
||||
const res = await listSupplierInput({
|
||||
projectId: currentProject.value?.id,
|
||||
pageNum: 1,
|
||||
state: 'finish',
|
||||
pageSize: 10000
|
||||
});
|
||||
supplierOptions.value = res.rows;
|
||||
};
|
||||
|
||||
/** 文件操作 **/
|
||||
@ -304,6 +315,7 @@ const listeningProject = watch(
|
||||
queryParams.value.projectId = nid;
|
||||
form.value.projectId = nid;
|
||||
console.log('监听项目id', queryParams.value.projectId, form.value.projectId);
|
||||
getSupplierList();
|
||||
getList();
|
||||
}
|
||||
);
|
||||
@ -314,5 +326,6 @@ onUnmounted(() => {
|
||||
onMounted(() => {
|
||||
getDictList();
|
||||
getList();
|
||||
getSupplierList();
|
||||
});
|
||||
</script>
|
||||
|
@ -46,16 +46,11 @@
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['land:landBlock:remove']"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-table draggable v-loading="loading" :data="landBlockList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" label="序号" width="55" align="center" />
|
||||
<el-table-column label="地块编号" align="center" prop="landCode" />
|
||||
<el-table-column label="地块名称" align="center" prop="landName" />
|
||||
<el-table-column label="方阵" align="center" prop="unit" />
|
||||
@ -80,11 +75,9 @@
|
||||
</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="landBlockFormRef" :model="form" :rules="rules" label-width="100px">
|
||||
<!-- <el-form-item label="地块编号" prop="landCode">
|
||||
<el-input v-model="form.landCode" placeholder="请输入地块编号" />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="地块名称" prop="landName">
|
||||
<el-input v-model="form.landName" placeholder="请输入地块名称" />
|
||||
</el-form-item>
|
||||
@ -111,15 +104,25 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog draggable :title="dialogMatrix.title" v-model="dialogMatrix.visible" width="800px" append-to-body>
|
||||
<!-- 关联方阵弹窗(核心修改区域) -->
|
||||
<el-dialog draggable :title="dialogMatrix.title" v-model="dialogMatrix.visible" width="900px" append-to-body>
|
||||
<el-button type="primary" plain icon="Plus" @click="addUnitBoItem" style="margin-bottom: 15px">添加</el-button>
|
||||
<el-form ref="landBlockFormMatrixRef" :model="formM" :rules="rules" label-width="100px">
|
||||
<el-row v-for="(item, i) of unitBoList" :key="i">
|
||||
<el-col :span="9">
|
||||
<el-form-item label="方阵" prop="matrixId">
|
||||
<!-- 方阵表单:绑定unitBoList的索引,实现动态校验 -->
|
||||
<el-form ref="landBlockFormMatrixRef" :model="formM" label-width="100px">
|
||||
<el-row v-for="(item, i) of unitBoList" :key="i" class="mb-4">
|
||||
<!-- 方阵选择:必填校验 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
label="方阵"
|
||||
:prop="`unitBoList[${i}].unitProjectId`"
|
||||
:rules="[
|
||||
{ required: true, message: '请选择方阵', trigger: 'change' },
|
||||
{ type: 'array', min: 2, message: '请选择完整的方阵层级', trigger: 'change' }
|
||||
]"
|
||||
>
|
||||
<el-cascader
|
||||
:options="fangzhenList"
|
||||
placeholder="请选择"
|
||||
placeholder="请选择方阵"
|
||||
filterable
|
||||
:props="{ value: 'matrixId', label: 'name' }"
|
||||
v-model="item.unitProjectId"
|
||||
@ -127,18 +130,28 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="7">
|
||||
<el-form-item label="所属工区" prop="unitProjectArea">
|
||||
<!-- 所属工区:必填校验 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
label="所属工区"
|
||||
:prop="`unitBoList[${i}].unitProjectArea`"
|
||||
:rules="{ required: true, message: '请输入所属工区', trigger: 'blur' }"
|
||||
>
|
||||
<el-input v-model="item.unitProjectArea" placeholder="请输入所属工区" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 方阵状态:必填校验 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item label="方阵状态" prop="unitProjectStatus">
|
||||
<el-form-item
|
||||
label="方阵状态"
|
||||
:prop="`unitBoList[${i}].unitProjectStatus`"
|
||||
:rules="{ required: true, message: '请输入方阵状态', trigger: 'blur' }"
|
||||
>
|
||||
<el-input v-model="item.unitProjectStatus" placeholder="请输入方阵状态" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="1" style="margin-left: 15px">
|
||||
<el-button type="danger" icon="Delete" @click="removeUnitBoItem(i)"></el-button>
|
||||
<el-col :span="1" style="margin-left: 15px; display: flex; align-items: flex-end">
|
||||
<el-button style="margin-bottom: 18px" type="danger" icon="Delete" @click="removeUnitBoItem(i)"></el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
@ -153,44 +166,65 @@
|
||||
</template>
|
||||
|
||||
<script setup name="LandBlock" lang="ts">
|
||||
import { listLandBlock, getLandBlock, delLandBlock, LandUnit, addLandBlock, updateLandBlock, subMatrix,importLandBlock } from '@/api/system/landTransfer/landBlock';
|
||||
import {
|
||||
listLandBlock,
|
||||
getLandBlock,
|
||||
delLandBlock,
|
||||
LandUnit,
|
||||
addLandBlock,
|
||||
updateLandBlock,
|
||||
subMatrix,
|
||||
importLandBlock
|
||||
} from '@/api/system/landTransfer/landBlock';
|
||||
import { LandBlockVO, LandBlockQuery, LandBlockForm } from '@/api/system/landTransfer/landBlock/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { getCurrentInstance, ComponentInternalInstance, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { ElFormInstance, ElMessage } from 'element-plus';
|
||||
|
||||
// 类型定义补充(避免any)
|
||||
interface DialogOption {
|
||||
visible: boolean;
|
||||
title: string;
|
||||
}
|
||||
|
||||
interface UnitBoItem {
|
||||
unitProjectArea: string;
|
||||
unitProjectStatus: string;
|
||||
unitProjectId: (string | number)[]; // 级联选择值(数组)
|
||||
}
|
||||
|
||||
// 基础实例与Store
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
|
||||
// 响应式数据
|
||||
const landBlockList = ref<LandBlockVO[]>([]);
|
||||
const fangzhenList = ref([]); //方阵列表数据
|
||||
const fangzhenList = ref<any[]>([]); // 方阵列表(实际项目建议定义具体类型)
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const unitBoList = ref([
|
||||
{
|
||||
unitProjectArea: '1',
|
||||
unitProjectStatus: '1',
|
||||
unitProjectId: []
|
||||
}
|
||||
]);
|
||||
const uploadRef = ref<any>(null); // upload组件ref
|
||||
|
||||
// 方阵表单数据(核心修改:初始值为空,避免默认填充无效数据)
|
||||
const unitBoList = ref<UnitBoItem[]>([{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }]);
|
||||
|
||||
// 表格选择相关
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
// 表单Ref
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const landBlockFormRef = ref<ElFormInstance>();
|
||||
const landBlockFormMatrixRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const dialogMatrix = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '选择方阵'
|
||||
});
|
||||
// 弹窗配置
|
||||
const dialog = reactive<DialogOption>({ visible: false, title: '' });
|
||||
const dialogMatrix = reactive<DialogOption>({ visible: false, title: '选择方阵' });
|
||||
|
||||
// 初始表单数据
|
||||
const initFormData: LandBlockForm = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
@ -202,11 +236,11 @@ const initFormData: LandBlockForm = {
|
||||
farmerCount: undefined,
|
||||
remark: undefined
|
||||
};
|
||||
|
||||
// 核心数据(含表单规则)
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
formM: {
|
||||
landId: undefined
|
||||
},
|
||||
formM: { landId: undefined }, // 方阵关联表单(仅存地块ID)
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
@ -219,6 +253,7 @@ const data = reactive({
|
||||
farmerCount: undefined,
|
||||
params: {}
|
||||
},
|
||||
// 地块表单规则(原有规则保留)
|
||||
rules: {
|
||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||
@ -229,216 +264,285 @@ const data = reactive({
|
||||
|
||||
const { queryParams, form, rules, formM } = toRefs(data);
|
||||
|
||||
/** 查询地块信息列表 */
|
||||
/** 查询地块列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await listLandBlock(queryParams.value);
|
||||
landBlockList.value = res.rows;
|
||||
total.value = res.total;
|
||||
} catch (err) {
|
||||
proxy?.$modal.msgError('获取地块列表失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
/** 地块表单取消 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
/** 地块表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
landBlockFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
/** 搜索提交 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
/** 搜索重置 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
/** 表格选择变化 */
|
||||
const handleSelectionChange = (selection: LandBlockVO[]) => {
|
||||
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;
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
/** 新增地块 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '添加地块信息';
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
/** 编辑地块 */
|
||||
const handleUpdate = async (row?: LandBlockVO) => {
|
||||
reset();
|
||||
const _id = row?.id || ids.value[0];
|
||||
if (!_id) return proxy?.$modal.msgWarning('请选择要编辑的地块');
|
||||
|
||||
try {
|
||||
const res = await getLandBlock(_id);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = '修改地块信息';
|
||||
} catch (err) {
|
||||
proxy?.$modal.msgError('获取地块详情失败');
|
||||
}
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
/** 提交地块表单 */
|
||||
const submitForm = () => {
|
||||
landBlockFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
if (!valid) return;
|
||||
|
||||
buttonLoading.value = true;
|
||||
try {
|
||||
if (form.value.id) {
|
||||
await updateLandBlock(form.value).finally(() => (buttonLoading.value = false));
|
||||
await updateLandBlock(form.value);
|
||||
} else {
|
||||
await addLandBlock(form.value).finally(() => (buttonLoading.value = false));
|
||||
await addLandBlock(form.value);
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
} catch (err) {
|
||||
proxy?.$modal.msgError(form.value.id ? '修改失败' : '新增失败');
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
/** 删除地块 */
|
||||
const handleDelete = async (row?: LandBlockVO) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除地块信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||
if (!_ids.length) return proxy?.$modal.msgWarning('请选择要删除的地块');
|
||||
|
||||
try {
|
||||
await proxy?.$modal.confirm(`是否确认删除地块信息编号为"${_ids}"的数据项?`);
|
||||
await delLandBlock(_ids);
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
await getList();
|
||||
} catch (err) {
|
||||
// 取消确认时不提示错误
|
||||
if (err !== 'cancel') proxy?.$modal.msgError('删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 获取方阵列表
|
||||
/** 获取方阵列表 */
|
||||
const getfangzhenList = async () => {
|
||||
if (!currentProject.value?.id) return;
|
||||
|
||||
loading.value = true;
|
||||
const res = await subMatrix(currentProject.value?.id);
|
||||
res.data.forEach((item) => {
|
||||
item.children.forEach((item2) => {
|
||||
item2.matrixId = item2.name + '_' + item2.matrixId;
|
||||
try {
|
||||
const res = await subMatrix(currentProject.value.id);
|
||||
// 处理方阵数据(级联选择需父子结构,此处保留原有逻辑)
|
||||
res.data.forEach((item: any) => {
|
||||
item.children?.forEach((item2: any) => {
|
||||
item2.matrixId = `${item2.name}_${item2.matrixId}`; // 拼接名称+ID,便于后续拆分
|
||||
});
|
||||
});
|
||||
fangzhenList.value = res.data;
|
||||
} catch (err) {
|
||||
proxy?.$modal.msgError('获取方阵列表失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleView = async (row) => {
|
||||
// 关联方阵
|
||||
/** 关联方阵(核心修改:打开弹窗前强制重置表单) */
|
||||
const handleView = async (row: LandBlockVO) => {
|
||||
if (!row?.id) return proxy?.$modal.msgWarning('请选择有效的地块');
|
||||
|
||||
// 1. 重置方阵表单(清空历史数据)
|
||||
resetMatrix();
|
||||
// 2. 绑定当前地块ID
|
||||
formM.value.landId = row.id;
|
||||
// 3. 打开弹窗
|
||||
dialogMatrix.visible = true;
|
||||
dialogMatrix.title = '关联方阵';
|
||||
data.formM.landId = row.id;
|
||||
dialogMatrix.title = `关联方阵(地块:${row.landName || row.landCode})`;
|
||||
};
|
||||
// 动态添加unitBoList项
|
||||
|
||||
/** 新增方阵表单项 */
|
||||
const addUnitBoItem = () => {
|
||||
unitBoList.value.push({
|
||||
unitProjectArea: '',
|
||||
unitProjectStatus: '',
|
||||
unitProjectId: []
|
||||
unitProjectId: [] // 级联选择初始为空数组
|
||||
});
|
||||
};
|
||||
|
||||
// 移除unitBoList项
|
||||
/** 删除方阵表单项 */
|
||||
const removeUnitBoItem = (index: number) => {
|
||||
if (unitBoList.value.length > 1) {
|
||||
unitBoList.value.splice(index, 1);
|
||||
} else {
|
||||
proxy?.$modal.msgWarning('至少保留一项');
|
||||
if (unitBoList.value.length <= 1) {
|
||||
return proxy?.$modal.msgWarning('至少保留一项方阵配置');
|
||||
}
|
||||
unitBoList.value.splice(index, 1);
|
||||
// 重置表单校验状态(避免删除后残留校验提示)
|
||||
landBlockFormMatrixRef.value?.clearValidate();
|
||||
};
|
||||
|
||||
/** 提交方阵关联表单 */
|
||||
const submitFormMatrix = () => {
|
||||
landBlockFormMatrixRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
var arr = [];
|
||||
unitBoList.value.forEach((item) => {
|
||||
let str = item.unitProjectId[1].split('_');
|
||||
arr.push({
|
||||
unitProjectArea: item.unitProjectArea,
|
||||
unitProjectStatus: item.unitProjectStatus,
|
||||
unitProjectId: str[1],
|
||||
unitProjectName: str[0]
|
||||
if (!valid) return;
|
||||
if (!formM.value.landId) return proxy?.$modal.msgWarning('地块ID异常,请重新选择地块');
|
||||
|
||||
try {
|
||||
// 处理方阵数据(拆分名称+ID)
|
||||
const unitBoListParams = unitBoList.value.map((item) => {
|
||||
const [unitProjectName, unitProjectId] = item.unitProjectId[1]?.split('_') || [];
|
||||
if (!unitProjectId) throw new Error('方阵ID解析失败,请重新选择方阵');
|
||||
|
||||
return {
|
||||
unitProjectArea: item.unitProjectArea.trim(),
|
||||
unitProjectStatus: item.unitProjectStatus.trim(),
|
||||
unitProjectId: unitProjectId, // 纯ID(后端需要)
|
||||
unitProjectName: unitProjectName // 名称(可选,用于显示)
|
||||
};
|
||||
});
|
||||
|
||||
// 调用关联接口
|
||||
const res = await LandUnit({
|
||||
landId: formM.value.landId,
|
||||
unitBoList: unitBoListParams
|
||||
});
|
||||
var res = await LandUnit({ ...formM.value, unitBoList: arr });
|
||||
if (res.code == 200) {
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
|
||||
if (res.code === 200) {
|
||||
proxy?.$modal.msgSuccess('关联方阵成功');
|
||||
dialogMatrix.visible = false;
|
||||
await getList();
|
||||
await getList(); // 刷新地块列表
|
||||
} else {
|
||||
proxy?.$modal.msgError(res.msg);
|
||||
proxy?.$modal.msgError(res.msg || '关联失败');
|
||||
}
|
||||
} catch (err: any) {
|
||||
proxy?.$modal.msgError(err.msg || '关联过程异常');
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 取消按钮 */
|
||||
|
||||
/** 方阵表单取消 */
|
||||
const cancelMatrix = () => {
|
||||
resetMatrix();
|
||||
dialogMatrix.visible = false;
|
||||
};
|
||||
/** 表单重置 */
|
||||
|
||||
/** 方阵表单重置(核心修改:清空所有数据+重置校验) */
|
||||
const resetMatrix = () => {
|
||||
data.formM.landId = '';
|
||||
unitBoList.value = [
|
||||
{
|
||||
unitProjectArea: '1',
|
||||
unitProjectStatus: '1',
|
||||
unitProjectId: []
|
||||
// 1. 清空地块ID
|
||||
formM.value.landId = undefined;
|
||||
// 2. 重置方阵列表(仅保留一个空项)
|
||||
unitBoList.value = [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }];
|
||||
// 3. 重置表单校验状态
|
||||
if (landBlockFormMatrixRef.value) {
|
||||
landBlockFormMatrixRef.value.resetFields();
|
||||
landBlockFormMatrixRef.value.clearValidate();
|
||||
}
|
||||
];
|
||||
landBlockFormMatrixRef.value?.resetFields();
|
||||
};
|
||||
//监听项目id刷新数据
|
||||
|
||||
/** 监听项目变化,刷新数据 */
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
queryParams.value.projectId = nid;
|
||||
getfangzhenList();
|
||||
getList();
|
||||
(newId) => {
|
||||
if (newId) {
|
||||
queryParams.value.projectId = newId;
|
||||
getfangzhenList(); // 刷新方阵列表
|
||||
getList(); // 刷新地块列表
|
||||
}
|
||||
},
|
||||
{ immediate: true } // 初始加载时执行一次
|
||||
);
|
||||
|
||||
// 导入文件
|
||||
const handleImport = (options:any) => {
|
||||
/** 导入Excel */
|
||||
const handleImport = (options: { file: File }) => {
|
||||
if (!currentProject.value?.id) return proxy?.$modal.msgWarning('请先选择项目');
|
||||
if (!options.file) return proxy?.$modal.msgWarning('请选择Excel文件');
|
||||
|
||||
loading.value = true;
|
||||
let formData = new FormData();
|
||||
const formData = new FormData();
|
||||
formData.append('file', options.file);
|
||||
importLandBlock(currentProject.value?.id,formData).then((res) => {
|
||||
if (res.code == 200) {
|
||||
proxy.$modal.msgSuccess(res.msg || '导入成功');
|
||||
|
||||
importLandBlock(currentProject.value.id, formData)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
proxy?.$modal.msgSuccess(res.msg || '导入成功');
|
||||
getList();
|
||||
getfangzhenList();
|
||||
} else {
|
||||
proxy?.$modal.msgError(res.msg || '导入失败');
|
||||
}
|
||||
}).catch((err) => {
|
||||
proxy.$modal.msgError(err.msg || '导入失败');
|
||||
}).finally(() => {
|
||||
})
|
||||
.catch((err) => {
|
||||
proxy?.$modal.msgError(err.msg || '导入接口异常');
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 下载模板
|
||||
/** 下载导入模板 */
|
||||
const downloadTemplate = () => {
|
||||
// 导出模版文件
|
||||
try {
|
||||
// 创建a标签
|
||||
const link = document.createElement('a');
|
||||
// 设置PDF文件路径 - 相对于public目录
|
||||
link.href = '/landBlock.xlsx';
|
||||
// 设置下载后的文件名
|
||||
link.download = '地块信息导入模板.xlsx';
|
||||
// 触发点击
|
||||
link.href = '/landBlock.xlsx'; // 模板路径(需确保public目录下存在该文件)
|
||||
link.download = '地块信息导入模板.xlsx'; // 下载后文件名
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
} catch (error) {
|
||||
alert('下载失败,请重试');
|
||||
link.click(); // 触发下载
|
||||
} catch (err) {
|
||||
proxy?.$modal.msgError('模板下载失败,请重试');
|
||||
} finally {
|
||||
document.body.removeChild(link); // 清理DOM
|
||||
}
|
||||
};
|
||||
|
||||
/** 生命周期:组件卸载时清理监听 */
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
|
||||
/** 生命周期:组件挂载时初始化数据 */
|
||||
onMounted(() => {
|
||||
getList();
|
||||
getfangzhenList();
|
||||
|
@ -1,8 +1,37 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<div class="p-2 detailbox">
|
||||
<div class="box1">
|
||||
<div>
|
||||
<div>
|
||||
<span>设计面积</span>
|
||||
<span>{{ detailInfo.designArea }} 亩</span>
|
||||
</div>
|
||||
<el-icon :size="50" color="#3176ff">
|
||||
<Postcard />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<span>已流转面积</span>
|
||||
<span>{{ detailInfo.transferAea }} 亩</span>
|
||||
</div>
|
||||
<el-icon :size="50" color="#3176ff">
|
||||
<Postcard />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<span>租金</span>
|
||||
<span>{{ detailInfo.landRent / 1000 }} 万元</span>
|
||||
</div>
|
||||
<el-icon :size="50" color="#3176ff">
|
||||
<Postcard />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="110px">
|
||||
<el-form-item label="对应地块" prop="landBlockId">
|
||||
<el-select v-model="queryParams.landBlockId" clearable placeholder="请选择对应地块">
|
||||
@ -12,8 +41,9 @@
|
||||
<el-form-item label="流转台账状态" prop="transferStatus">
|
||||
<el-select v-model="queryParams.transferStatus" placeholder="请选择流转台账状态" clearable>
|
||||
<el-option label="待流转" :value="0"></el-option>
|
||||
<el-option label="已流转" :value="1"></el-option> </el-select
|
||||
></el-form-item>
|
||||
<el-option label="已流转" :value="1"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="责任人" prop="responsiblePerson">
|
||||
<el-input v-model="queryParams.responsiblePerson" placeholder="请输入责任人" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
@ -31,15 +61,7 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:landTransferLedger:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-tag size="large" type="primary">设计面积:{{ detailInfo.designArea }}亩</el-tag>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-tag size="large" type="success">已流转面积:{{ detailInfo.transferAea }}亩</el-tag>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-tag size="large" type="warning">租金:{{ detailInfo.landRent / 1000 }}万元</el-tag>
|
||||
</el-col>
|
||||
<el-col :span="6"></el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
@ -81,90 +103,107 @@
|
||||
<el-form-item label="对应地块" prop="landBlockId">
|
||||
<el-select v-model="form.landBlockId" clearable placeholder="请选择对应地块" @change="handleLandBlockChange">
|
||||
<el-option v-for="item in landBlockList" :key="item.id" :label="item.landName" :value="item.id" />
|
||||
</el-select> </el-form-item
|
||||
></el-col>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="进场道路" prop="enterRoadId">
|
||||
<el-select v-model="form.enterRoadId" clearable placeholder="请选择对应地块">
|
||||
<el-option v-for="item in enterRoadList" :key="item.id" :label="item.roadName" :value="item.id" />
|
||||
</el-select> </el-form-item
|
||||
></el-col>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="土地类型" prop="landType">
|
||||
<el-select v-model="form.landType" placeholder="请选择土地类型" clearable>
|
||||
<el-option v-for="dict in land_type" :key="dict.value" :label="dict.label" :value="dict.value" /> </el-select></el-form-item
|
||||
></el-col>
|
||||
<el-option v-for="dict in land_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="流转台账状态" prop="transferStatus">
|
||||
<el-select v-model="form.transferStatus" :disabled="!form.id" placeholder="请选择流转台账状态" clearable>
|
||||
<el-option
|
||||
v-for="dict in land_transfer_status"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/> </el-select></el-form-item
|
||||
></el-col>
|
||||
<el-select v-model="form.transferStatus" :disabled="!form.id" placeholder="请选择流转台账状态" clearable @change="calcTransferRatio">
|
||||
<el-option v-for="dict in land_transfer_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计面积(亩)" prop="designArea">
|
||||
<el-input type="number" v-model="form.designArea" placeholder="请输入设计面积" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="责任人" prop="responsiblePerson">
|
||||
<el-input v-model="form.responsiblePerson" placeholder="请输入责任人" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col v-if="form.transferStatus != '2'" :span="12"
|
||||
><el-form-item label="预计完成日期" prop="expectedFinishDate">
|
||||
<el-input type="number" v-model="form.designArea" placeholder="请输入设计面积" @input="calcTransferRatio" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="责任人" prop="responsiblePerson">
|
||||
<el-input v-model="form.responsiblePerson" placeholder="请输入责任人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus != '2'" :span="12">
|
||||
<el-form-item label="预计完成日期" prop="expectedFinishDate">
|
||||
<el-date-picker clearable v-model="form.expectedFinishDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择预计完成时间">
|
||||
</el-date-picker> </el-form-item
|
||||
></el-col>
|
||||
<el-col v-if="form.transferStatus == '1'" :span="12"
|
||||
><el-form-item label="已流转面积(亩)" prop="transferAea">
|
||||
<el-input v-model="form.transferAea" type="number" placeholder="请输入已流转面积" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col v-if="form.transferStatus == '1'" :span="12"
|
||||
><el-form-item label="流转比例(%)" prop="transferRatio">
|
||||
<el-input v-model="form.transferRatio" type="number" placeholder="请输入流转比例" /> </el-form-item
|
||||
></el-col>
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus == '1'" :span="12">
|
||||
<el-form-item label="已流转面积(亩)" prop="transferAea">
|
||||
<el-input v-model="form.transferAea" type="number" placeholder="请输入已流转面积" @input="calcTransferRatio" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- 流转比例:改为禁用输入,自动计算展示 -->
|
||||
<el-col v-if="form.transferStatus == '1'" :span="12">
|
||||
<el-form-item label="流转比例(%)" prop="transferRatio">
|
||||
<el-input v-model="form.transferRatio" type="text" :disabled="true" placeholder="自动计算中..." />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus == '1'" :span="12">
|
||||
<el-form-item label="土地租金(元)" prop="landRent">
|
||||
<el-input type="number" v-model="form.landRent" placeholder="请输入土地租金" /> </el-form-item
|
||||
></el-col>
|
||||
<el-input type="number" v-model="form.landRent" placeholder="请输入土地租金" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus == '1'" :span="12">
|
||||
<el-form-item label="青苗赔偿(元)" prop="seedlingCompensation">
|
||||
<el-input v-model="form.seedlingCompensation" type="number" placeholder="请输入青苗赔偿" /> </el-form-item
|
||||
></el-col>
|
||||
<el-input v-model="form.seedlingCompensation" type="number" placeholder="请输入青苗赔偿" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus == '1'" :span="12">
|
||||
<el-form-item label="总金额(元)" prop="totalAmount">
|
||||
<el-input type="number" v-model="form.totalAmount" placeholder="请输入总金额" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col v-if="form.transferStatus == '2'" :span="12"
|
||||
><el-form-item label="不签合同面积(亩)" prop="noContractArea">
|
||||
<el-input v-model="form.noContractArea" type="number" placeholder="请输入不签合同面积" /> </el-form-item
|
||||
></el-col>
|
||||
<el-input type="number" v-model="form.totalAmount" placeholder="请输入总金额" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus == '2'" :span="12">
|
||||
<el-form-item label="不签合同面积(亩)" prop="noContractArea">
|
||||
<el-input v-model="form.noContractArea" type="number" placeholder="请输入不签合同面积" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus == '2'" :span="12">
|
||||
<el-form-item label="不测量面积(亩)" prop="noSurveyArea">
|
||||
<el-input v-model="form.noSurveyArea" type="number" placeholder="请输入不测量面积" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col v-if="form.transferStatus == '2'" :span="24"
|
||||
><el-form-item label="不签合同原因" prop="noContractReason">
|
||||
<el-input v-model="form.noContractReason" type="textarea" placeholder="请输入内容" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col v-if="form.transferStatus == '2'" :span="24"
|
||||
><el-form-item label="不流转原因" prop="nonTransferReason">
|
||||
<el-input v-model="form.nonTransferReason" type="textarea" placeholder="请输入内容" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col v-if="form.transferStatus == '1'" :span="24"
|
||||
><el-form-item label="状态说明" prop="statusDescription">
|
||||
<el-input v-model="form.statusDescription" type="textarea" placeholder="请输入内容" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col v-if="form.transferStatus == '1'" :span="24"
|
||||
><el-form-item label="问题总结" prop="issueSummary">
|
||||
<el-input v-model="form.issueSummary" type="textarea" placeholder="请输入内容" /> </el-form-item
|
||||
></el-col>
|
||||
<el-input v-model="form.noSurveyArea" type="number" placeholder="请输入不测量面积" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus == '2'" :span="24">
|
||||
<el-form-item label="不签合同原因" prop="noContractReason">
|
||||
<el-input v-model="form.noContractReason" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus == '2'" :span="24">
|
||||
<el-form-item label="不流转原因" prop="nonTransferReason">
|
||||
<el-input v-model="form.nonTransferReason" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus == '1'" :span="24">
|
||||
<el-form-item label="状态说明" prop="statusDescription">
|
||||
<el-input v-model="form.statusDescription" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus == '1'" :span="24">
|
||||
<el-form-item label="问题总结" prop="issueSummary">
|
||||
<el-input v-model="form.issueSummary" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="form.transferStatus == '1'" :span="24">
|
||||
<el-form-item label="下一步策略" prop="nextStrategy">
|
||||
<el-input v-model="form.nextStrategy" type="textarea" placeholder="请输入内容" /> </el-form-item
|
||||
></el-col>
|
||||
<el-input v-model="form.nextStrategy" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
@ -190,6 +229,20 @@ import { listEnterRoad } from '@/api/system/landTransfer/enterRoad';
|
||||
import { LandTransferLedgerVO, LandTransferLedgerQuery, LandTransferLedgerForm } from '@/api/system/landTransfer/landTransferLedger/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { listLandBlock } from '@/api/system/landTransfer/landBlock';
|
||||
import { getCurrentInstance, ComponentInternalInstance, watch, onUnmounted, onMounted } from 'vue';
|
||||
import { ElFormInstance } from 'element-plus';
|
||||
|
||||
// 类型定义补充
|
||||
interface DialogOption {
|
||||
visible: boolean;
|
||||
title: string;
|
||||
}
|
||||
interface PageData<T, Q> {
|
||||
form: T;
|
||||
queryParams: Q;
|
||||
rules: Record<string, any[]>;
|
||||
}
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
@ -207,6 +260,7 @@ const landBlockList = ref([]);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const landTransferLedgerFormRef = ref<ElFormInstance>();
|
||||
const enterRoadList = ref([]);
|
||||
// 字典数据
|
||||
const { land_type, land_transfer_status } = toRefs<any>(proxy?.useDict('land_type', 'land_transfer_status'));
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
@ -214,7 +268,8 @@ const dialog = reactive<DialogOption>({
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData = {
|
||||
// 表单初始数据
|
||||
const initFormData: LandTransferLedgerForm = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
landType: undefined,
|
||||
@ -237,6 +292,8 @@ const initFormData = {
|
||||
noSurveyArea: undefined,
|
||||
nonTransferReason: undefined
|
||||
};
|
||||
|
||||
// 核心数据响应式对象
|
||||
const data = reactive<PageData<LandTransferLedgerForm, LandTransferLedgerQuery>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
@ -264,9 +321,40 @@ const data = reactive<PageData<LandTransferLedgerForm, LandTransferLedgerQuery>>
|
||||
rules: {
|
||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||
landType: [{ required: true, message: '土地类型不能为空', trigger: 'change' }]
|
||||
landType: [{ required: true, message: '土地类型不能为空', trigger: 'change' }],
|
||||
transferRatio: [
|
||||
// 动态校验:仅已流转状态下必填
|
||||
{
|
||||
required: true,
|
||||
message: '流转比例不能为空',
|
||||
trigger: ['blur', 'change'],
|
||||
validator: (rule, value, callback) => {
|
||||
if (data.form.transferStatus !== '1') {
|
||||
callback(); // 非已流转状态跳过校验
|
||||
return;
|
||||
}
|
||||
if (value === undefined || value === null || value === '') {
|
||||
callback(new Error('流转比例不能为空'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
},
|
||||
// 比例范围校验(0-100)
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (value < 0 || value > 100) {
|
||||
callback(new Error('流转比例必须在 0-100 之间'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
const detailInfo = ref({
|
||||
transferAea: 0,
|
||||
transferRatio: 0,
|
||||
@ -274,18 +362,53 @@ const detailInfo = ref({
|
||||
});
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/**
|
||||
* 自动计算流转比例:(已流转面积 / 设计面积) × 100,保留2位小数,最大100%
|
||||
*/
|
||||
const calcTransferRatio = () => {
|
||||
// 仅已流转状态下计算
|
||||
if (form.value.transferStatus !== '1') {
|
||||
form.value.transferRatio = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
// 转换为数字(避免字符串计算)
|
||||
const designArea = Number(form.value.designArea) || 0;
|
||||
const transferAea = Number(form.value.transferAea) || 0;
|
||||
|
||||
// 边界处理:设计面积为0时避免报错
|
||||
if (designArea === 0) {
|
||||
form.value.transferRatio = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// 核心计算:限制最大100%,保留2位小数
|
||||
const ratio = Math.min((transferAea / designArea) * 100, 100);
|
||||
form.value.transferRatio = Number(ratio.toFixed(2));
|
||||
};
|
||||
|
||||
/** 查询项目土地流转台账列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await listLandTransferLedger(queryParams.value);
|
||||
landTransferLedgerList.value = res.rows;
|
||||
total.value = res.total;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取地块统计信息 */
|
||||
const getLandBlockList = async () => {
|
||||
let res = await landTransferLedgerCount(currentProject.value?.id);
|
||||
try {
|
||||
const res = await landTransferLedgerCount(currentProject.value?.id);
|
||||
detailInfo.value = res.data;
|
||||
} catch (error) {
|
||||
console.error('获取地块统计信息失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
dialog.visible = false;
|
||||
@ -313,92 +436,176 @@ const resetQuery = () => {
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: LandTransferLedgerVO[]) => {
|
||||
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;
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
form.value.transferStatus = '0';
|
||||
dialog.visible = true;
|
||||
form.value.transferStatus = '0'; // 默认待流转
|
||||
enterRoadList.value = [];
|
||||
dialog.title = '添加项目土地流转台账';
|
||||
dialog.visible = true;
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: LandTransferLedgerVO) => {
|
||||
reset();
|
||||
form.value.landBlockId = row?.landBlockId;
|
||||
getListRoad();
|
||||
const _id = row?.id || ids.value[0];
|
||||
if (!_id) return;
|
||||
|
||||
try {
|
||||
// 获取编辑数据
|
||||
const res = await getLandTransferLedger(_id);
|
||||
Object.assign(form.value, res.data);
|
||||
console.log(form.value);
|
||||
|
||||
dialog.visible = true;
|
||||
// 回显地块对应的道路列表
|
||||
form.value.landBlockId = row?.landBlockId;
|
||||
await getListRoad();
|
||||
// 初始化计算流转比例
|
||||
calcTransferRatio();
|
||||
// 打开弹窗
|
||||
dialog.title = '修改项目土地流转台账';
|
||||
dialog.visible = true;
|
||||
} catch (error) {
|
||||
console.error('获取编辑数据失败:', error);
|
||||
proxy?.$modal.msgError('加载数据失败,请重试');
|
||||
}
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
landTransferLedgerFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
if (!valid) return;
|
||||
|
||||
buttonLoading.value = true;
|
||||
try {
|
||||
if (form.value.id) {
|
||||
await updateLandTransferLedger(form.value).finally(() => (buttonLoading.value = false));
|
||||
await updateLandTransferLedger(form.value);
|
||||
} else {
|
||||
await addLandTransferLedger(form.value).finally(() => (buttonLoading.value = false));
|
||||
await addLandTransferLedger(form.value);
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
await getLandBlockList(); // 刷新统计信息
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('操作失败,请重试');
|
||||
console.error('提交表单失败:', error);
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: LandTransferLedgerVO) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除项目土地流转台账编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||
if (!_ids.length) return;
|
||||
|
||||
try {
|
||||
await proxy?.$modal.confirm(`是否确认删除项目土地流转台账编号为"${_ids}"的数据项?`);
|
||||
await delLandTransferLedger(_ids);
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
await getList();
|
||||
await getLandBlockList(); // 刷新统计信息
|
||||
} catch (error) {
|
||||
console.error('删除数据失败:', error);
|
||||
if (error !== 'cancel') {
|
||||
// 排除用户取消确认的情况
|
||||
proxy?.$modal.msgError('删除失败,请重试');
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
// 选择地块
|
||||
const handleLandBlockChange = (val) => {
|
||||
getListRoad();
|
||||
|
||||
/** 选择地块后加载对应道路 */
|
||||
const handleLandBlockChange = async () => {
|
||||
await getListRoad();
|
||||
};
|
||||
/** 查询地块信息列表 */
|
||||
|
||||
/** 查询地块列表 */
|
||||
const getListLand = async () => {
|
||||
try {
|
||||
const res = await listLandBlock({
|
||||
pageNum: 1,
|
||||
pageSize: 10000,
|
||||
projectId: currentProject.value?.id
|
||||
});
|
||||
landBlockList.value = res.rows;
|
||||
} catch (error) {
|
||||
console.error('获取地块列表失败:', error);
|
||||
}
|
||||
};
|
||||
/** 查询进场道路信息列表 */
|
||||
|
||||
/** 查询进场道路列表(按地块筛选) */
|
||||
const getListRoad = async () => {
|
||||
const res = await listEnterRoad({ pageNum: 1, pageSize: 10000, projectId: currentProject.value?.id, landBlockId: form.value.landBlockId });
|
||||
try {
|
||||
const res = await listEnterRoad({
|
||||
pageNum: 1,
|
||||
pageSize: 10000,
|
||||
projectId: currentProject.value?.id,
|
||||
landBlockId: form.value.landBlockId
|
||||
});
|
||||
enterRoadList.value = res.rows;
|
||||
} catch (error) {
|
||||
console.error('获取进场道路列表失败:', error);
|
||||
}
|
||||
};
|
||||
//监听项目id刷新数据
|
||||
|
||||
/** 监听项目切换,刷新数据 */
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
queryParams.value.projectId = nid;
|
||||
getLandBlockList();
|
||||
getListLand();
|
||||
getList();
|
||||
async (newId) => {
|
||||
if (newId) {
|
||||
queryParams.value.projectId = newId;
|
||||
await Promise.all([getLandBlockList(), getListLand(), getList()]);
|
||||
}
|
||||
},
|
||||
{ immediate: true } // 初始加载时触发
|
||||
);
|
||||
|
||||
/** 组件卸载时清理监听 */
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
|
||||
/** 组件挂载时初始化数据 */
|
||||
onMounted(() => {
|
||||
getLandBlockList();
|
||||
getList();
|
||||
getListLand();
|
||||
Promise.all([getLandBlockList(), getListLand(), getList()]);
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.detailbox {
|
||||
width: 100%;
|
||||
.box1 {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 20px 0;
|
||||
> div {
|
||||
width: 300px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20px 15px;
|
||||
border: 1px solid #e7e7e7;
|
||||
margin: 0 20px;
|
||||
border-radius: 6px;
|
||||
> div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
> span:first-child {
|
||||
font-size: 16px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
> span:last-child {
|
||||
font-size: 24px;
|
||||
/* font-weight: bold; */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -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">
|
||||
@ -9,13 +8,11 @@
|
||||
<el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="类别编码" prop="deptCategory">
|
||||
<el-input v-model="queryParams.deptCategory" placeholder="请输入类别编码" clearable style="width: 240px"
|
||||
@keyup.enter="handleQuery" />
|
||||
<el-input v-model="queryParams.deptCategory" placeholder="请输入类别编码" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="部门状态" clearable>
|
||||
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label"
|
||||
:value="dict.value" />
|
||||
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
@ -31,8 +28,7 @@
|
||||
<template #header>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增
|
||||
</el-button>
|
||||
<el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增 </el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||
@ -41,8 +37,14 @@
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table ref="deptTableRef" v-loading="loading" :data="deptList" row-key="deptId"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }" :default-expand-all="isExpandAll">
|
||||
<el-table
|
||||
ref="deptTableRef"
|
||||
v-loading="loading"
|
||||
:data="deptList"
|
||||
row-key="deptId"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
:default-expand-all="isExpandAll"
|
||||
>
|
||||
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
|
||||
<el-table-column prop="deptCategory" align="center" label="类别编码" width="200"></el-table-column>
|
||||
<el-table-column prop="deptType" align="center" label="部门类型" width="200">
|
||||
@ -64,16 +66,13 @@
|
||||
<el-table-column fixed="right" align="center" label="操作">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="修改" placement="top">
|
||||
<el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit"
|
||||
@click="handleUpdate(scope.row)" />
|
||||
<el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
|
||||
</el-tooltip>
|
||||
<el-tooltip content="新增" placement="top" v-if="scope.row.deptType != '2' && scope.row.deptType != '5'">
|
||||
<el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus"
|
||||
@click="handleAdd(scope.row)" />
|
||||
<el-tooltip content="新增" placement="top">
|
||||
<el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button v-hasPermi="['system:dept:remove']" link type="primary" icon="Delete"
|
||||
@click="handleDelete(scope.row)" />
|
||||
<el-button v-hasPermi="['system:dept:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -85,9 +84,14 @@
|
||||
<el-row>
|
||||
<el-col v-if="form.parentId !== 0" :span="24">
|
||||
<el-form-item label="上级部门" prop="parentId">
|
||||
<el-tree-select v-model="form.parentId" :data="deptOptions"
|
||||
:props="{ value: 'deptId', label: 'deptName', children: 'children' }" value-key="deptId"
|
||||
placeholder="选择上级部门" check-strictly />
|
||||
<el-tree-select
|
||||
v-model="form.parentId"
|
||||
:data="deptOptions"
|
||||
:props="{ value: 'deptId', label: 'deptName', children: 'children' }"
|
||||
value-key="deptId"
|
||||
placeholder="选择上级部门"
|
||||
check-strictly
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@ -108,8 +112,7 @@
|
||||
<el-col :span="12">
|
||||
<el-form-item label="负责人" prop="leader">
|
||||
<el-select v-model="form.leader" placeholder="请选择负责人">
|
||||
<el-option v-for="item in deptUserList" :key="item.userId" :label="item.userName"
|
||||
:value="item.userId" />
|
||||
<el-option v-for="item in deptUserList" :key="item.userId" :label="item.userName" :value="item.userId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -126,32 +129,17 @@
|
||||
<el-col :span="12">
|
||||
<el-form-item label="部门状态">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
|
||||
}}</el-radio>
|
||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="部门类型">
|
||||
<el-select v-model="form.deptType" placeholder="请选择部门类型" @change="changeProject">
|
||||
<el-select v-model="form.deptType" placeholder="请选择部门类型">
|
||||
<el-option v-for="dict in sys_dept_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.deptType == '4'">
|
||||
<el-form-item label="所属项目" prop="projectId">
|
||||
<el-select v-model="form.projectId" placeholder="请选择所属项目">
|
||||
<el-option v-for="item in projectList" :key="item.id" :label="item.projectName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.deptType == '5'">
|
||||
<el-form-item label="分包单位" prop="contractorId">
|
||||
<el-select v-model="form.contractorId" placeholder="请选择分包单位">
|
||||
<el-option v-for="item in contractorList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
@ -336,16 +324,6 @@ const handleUpdate = async (row: DeptVO) => {
|
||||
dialog.title = '修改部门';
|
||||
};
|
||||
|
||||
const changeProject = async (val: any) => {
|
||||
if (val == '4' && (!projectList.value || !projectList.value.length)) {
|
||||
const res = await getDeptList();
|
||||
projectList.value = res.data;
|
||||
} else if (val == '5' && (!contractorList.value || !contractorList.value.length)) {
|
||||
const res = await optionProjectSelect(form.value.rowProjectId);
|
||||
contractorList.value = res;
|
||||
}
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
deptFormRef.value?.validate(async (valid: boolean) => {
|
||||
|
@ -174,8 +174,6 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="手机号码" prop="phonenumber">
|
||||
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
|
||||
@ -186,8 +184,6 @@
|
||||
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
|
||||
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
|
||||
@ -198,8 +194,6 @@
|
||||
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户性别">
|
||||
<el-select v-model="form.sex" placeholder="请选择">
|
||||
@ -207,15 +201,6 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="岗位">
|
||||
<el-select v-model="form.postIds" multiple placeholder="请选择">
|
||||
@ -229,9 +214,18 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="角色" prop="roleIds">
|
||||
<el-select v-model="form.roleIds" filterable multiple placeholder="请选择">
|
||||
<el-col :span="24">
|
||||
<el-row :gutter="20" v-for="(item, index) in form.projectRoles">
|
||||
<el-col :span="11" :offset="0">
|
||||
<el-form-item label="项目列表">
|
||||
<el-select v-model="item.projectId" placeholder="请选择">
|
||||
<el-option v-for="dict in projectOptions" :key="dict.id" :label="dict.shortName" :value="dict.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11" :offset="0">
|
||||
<el-form-item label="角色">
|
||||
<el-select v-model="item.roleIds" filterable multiple placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in roleOptions"
|
||||
:key="item.roleId"
|
||||
@ -242,8 +236,19 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="1" :offset="0">
|
||||
<el-button type="primary" circle icon="Plus" @click="handleAddProject" v-if="index == 0"></el-button>
|
||||
<el-button type="danger" circle icon="Delete" @click="delProject(index)" v-else></el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
||||
@ -317,8 +322,9 @@ import { RoleVO } from '@/api/system/role/types';
|
||||
import { PostVO } from '@/api/system/post/types';
|
||||
import { globalHeaders } from '@/utils/request';
|
||||
import { to } from 'await-to-js';
|
||||
import { getRoleList, optionselect } from '@/api/system/post';
|
||||
import { getProjectByDeptId, getRoleList, optionselect } from '@/api/system/post';
|
||||
import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue';
|
||||
import { listProject } from '@/api/project/project';
|
||||
|
||||
const router = useRouter();
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@ -337,6 +343,8 @@ const enabledDeptOptions = ref<DeptTreeVO[]>([]);
|
||||
const initPassword = ref<string>('');
|
||||
const postOptions = ref<PostVO[]>([]);
|
||||
const roleOptions = ref<RoleVO[]>([]);
|
||||
const projectOptions = ref<any[]>([]);
|
||||
|
||||
/*** 用户导入参数 */
|
||||
const upload = reactive<ImportOption>({
|
||||
// 是否显示弹出层(用户导入)
|
||||
@ -383,10 +391,15 @@ const initFormData: UserForm = {
|
||||
phonenumber: undefined,
|
||||
email: undefined,
|
||||
sex: undefined,
|
||||
projectRoles: [
|
||||
{
|
||||
projectId: '',
|
||||
roleIds: []
|
||||
}
|
||||
],
|
||||
status: '0',
|
||||
remark: '',
|
||||
postIds: [],
|
||||
roleIds: [],
|
||||
filePath: undefined
|
||||
};
|
||||
|
||||
@ -436,8 +449,7 @@ const initData: PageData<UserForm, UserQuery> = {
|
||||
message: '请输入正确的手机号码',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
roleIds: [{ required: true, message: '用户角色不能为空', trigger: 'blur' }]
|
||||
]
|
||||
}
|
||||
};
|
||||
const data = reactive<PageData<UserForm, UserQuery>>(initData);
|
||||
@ -473,6 +485,8 @@ const getDeptTree = async () => {
|
||||
const res = await api.deptTreeSelect({ isShow: '1' });
|
||||
deptOptions.value = res.data;
|
||||
enabledDeptOptions.value = filterDisabledDept(res.data);
|
||||
const projectList = await listProject();
|
||||
projectOptions.value = projectList.rows;
|
||||
};
|
||||
|
||||
/** 过滤禁用的部门 */
|
||||
@ -494,6 +508,19 @@ const handleNodeClick = (data: DeptVO) => {
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 部门选择变化 */
|
||||
const handleAddProject = () => {
|
||||
form.value.projectRoles.push({
|
||||
projectId: '',
|
||||
roleIds: []
|
||||
});
|
||||
};
|
||||
|
||||
/** 删除项目 */
|
||||
const delProject = (index: number) => {
|
||||
form.value.projectRoles.splice(index, 1);
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
@ -609,6 +636,13 @@ function submitFileForm() {
|
||||
/** 重置操作表单 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
form.value.projectRoles = [
|
||||
{
|
||||
projectId: '',
|
||||
roleIds: []
|
||||
}
|
||||
];
|
||||
|
||||
userFormRef.value?.resetFields();
|
||||
};
|
||||
/** 取消按钮 */
|
||||
@ -638,12 +672,32 @@ const handleUpdate = async (row?: UserForm) => {
|
||||
postOptions.value = data.posts;
|
||||
roleOptions.value = data.roles;
|
||||
form.value.postIds = data.postIds;
|
||||
form.value.roleIds = data.user.roleIds;
|
||||
form.value.projectRoles = data.projectRoles;
|
||||
form.value.password = '';
|
||||
const roleList = await getRoleList(form.value.deptId);
|
||||
|
||||
roleOptions.value = roleList.data;
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
for (let i = 0; i < form.value.projectRoles.length; i++) {
|
||||
const item = form.value.projectRoles[i];
|
||||
if (!item.projectId || item.projectId.length === 0) {
|
||||
proxy?.$modal.msgError(`第 ${i + 1} 行“项目列表”未填写`);
|
||||
return false; // 阻止提交
|
||||
}
|
||||
if (!item.roleIds || item.roleIds.length === 0) {
|
||||
proxy?.$modal.msgError(`第 ${i + 1} 行“角色”未填写`);
|
||||
return false; // 阻止提交
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
const isValid = validate();
|
||||
if (!isValid) return;
|
||||
userFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
|
||||
@ -683,10 +737,16 @@ onMounted(() => {
|
||||
async function handleDeptChange(value: number | string) {
|
||||
const response = await optionselect(value);
|
||||
const roleList = await getRoleList(value);
|
||||
|
||||
roleOptions.value = roleList.data;
|
||||
postOptions.value = response.data;
|
||||
form.value.postIds = [];
|
||||
form.value.roleIds = [];
|
||||
form.value.projectRoles = [
|
||||
{
|
||||
projectId: [],
|
||||
roleIds: []
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
const shuttleVisible = ref(false);
|
||||
|
@ -15,12 +15,14 @@
|
||||
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="toggleExpandAll(true)">一键展开</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="toggleExpandAll(false)">一键收起</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
@ -42,11 +44,16 @@
|
||||
type="warning"
|
||||
icon="view"
|
||||
@click="handleAudit()"
|
||||
v-if="versionsData.status == 'draft'"
|
||||
v-if="versionsData.status && versionsData.status == 'draft'"
|
||||
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
||||
>审核</el-button
|
||||
>
|
||||
<el-button type="warning" icon="view" @click="handleAudit()" v-else v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
||||
<el-button
|
||||
type="warning"
|
||||
icon="view"
|
||||
@click="handleAudit()"
|
||||
v-if="versionsData.status && versionsData.status != 'draft'"
|
||||
v-hasPermi="['tender:tenderPlanLimitList:getVersionDetail']"
|
||||
>查看流程</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
@ -58,12 +65,21 @@
|
||||
<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
|
||||
: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"
|
||||
@ -82,7 +98,7 @@
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleSave(scope.row)"
|
||||
@click="handleSave(scope.row, 'all')"
|
||||
v-if="scope.row.quantity && scope.row.quantity != 0"
|
||||
v-hasPermi="['tender:tenderPlanLimitList:edit']"
|
||||
:disabled="versionsData.status != 'draft'"
|
||||
@ -133,6 +149,8 @@ const versionMap = new Map();
|
||||
// 切换tab
|
||||
const handleTabChange = (tab: string) => {
|
||||
activeTab.value = tab;
|
||||
tableData.value = [];
|
||||
versionsData.value = {};
|
||||
getVersionNums();
|
||||
};
|
||||
//切换版本
|
||||
@ -205,6 +223,8 @@ const getSheetName = async () => {
|
||||
//获取表格数据
|
||||
const getTableData = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
|
||||
const params = {
|
||||
projectId: currentProject.value?.id,
|
||||
versions: queryForm.value.versions,
|
||||
@ -217,6 +237,8 @@ const getTableData = async () => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
//导入
|
||||
@ -257,18 +279,21 @@ const handleExport = () => {
|
||||
`招标一览表${queryForm.value.sheet}.xlsx`
|
||||
);
|
||||
};
|
||||
//确认修改
|
||||
const handleSave = (row: any) => {
|
||||
const modifyPrice = new Map();
|
||||
|
||||
const changePrice = (row: any) => {
|
||||
modifyPrice.set(row.id, row);
|
||||
// if (!row.unitPrice) {
|
||||
// modifyPrice.delete(row.id);
|
||||
// }
|
||||
};
|
||||
//修改单价
|
||||
const handleSave = (row?: any, type?: any) => {
|
||||
try {
|
||||
if (!row.unitPrice) {
|
||||
ElMessage({
|
||||
message: '请输入单价',
|
||||
type: 'warning'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (type == 'single') {
|
||||
loading.value = true;
|
||||
updatePrice(row).then((res) => {
|
||||
const list = [{ ...row, type: activeTab.value }];
|
||||
updatePrice(list).then((res) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage({
|
||||
message: '修改成功',
|
||||
@ -277,9 +302,28 @@ const handleSave = (row: any) => {
|
||||
getTableData();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (type == 'all') {
|
||||
loading.value = true;
|
||||
const list = [];
|
||||
modifyPrice.forEach((item) => {
|
||||
list.push({ ...item, type: activeTab.value });
|
||||
});
|
||||
updatePrice(list).then((res) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage({
|
||||
message: '修改成功',
|
||||
type: 'success'
|
||||
});
|
||||
getTableData();
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
loading.value = false;
|
||||
ElMessage({
|
||||
message: '修改失败',
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
|
@ -1,245 +1,78 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<el-card shadow="always">
|
||||
<el-form :model="queryForm" :inline="true">
|
||||
<el-form-item label="表名" prop="sheet">
|
||||
<el-select v-model="queryForm.sheet" placeholder="选择表名" @change="changeSheet">
|
||||
<el-option v-for="item in sheets" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="toggleExpandAll">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
class="upload-demo"
|
||||
:http-request="importExcel"
|
||||
:show-file-list="false"
|
||||
v-hasPermi="['bidding:biddingLimitList:importExcelFile']"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-button type="primary">导入excel</el-button>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleExport()" v-hasPermi="['bidding:biddingLimitList:export']">导出excel</el-button>
|
||||
<el-dialog v-model="dialogVisible" title="招标文件" width="500" draggable>
|
||||
<el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto">
|
||||
<el-form-item label="招标文件" prop="name">
|
||||
<file-upload
|
||||
v-model="form.costEstimationFile"
|
||||
:fileSize="100"
|
||||
:auto-upload="false"
|
||||
uploadUrl="/tender/biddingPlan/uploadBiddingDocuments"
|
||||
method="put"
|
||||
ref="fileUploadRef"
|
||||
:data="{
|
||||
projectId: currentProject?.id,
|
||||
type: planType,
|
||||
fileType: '1',
|
||||
bidStatus: '0',
|
||||
id: row.id
|
||||
}"
|
||||
showFileList
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</transition>
|
||||
<el-card shadow="never" class="mb8">
|
||||
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
|
||||
<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="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"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="price" label="总价" align="center">
|
||||
<template #default="scope">
|
||||
{{ scope.row.price }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="price" label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleSave(scope.row)"
|
||||
v-if="scope.row.quantity && scope.row.quantity != 0"
|
||||
v-hasPermi="['bidding:biddingLimitList:edit']"
|
||||
>修改</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="closeDialog()"> 取消 </el-button>
|
||||
<el-button type="primary" @click="submitForm()">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { obtainAllVersionNumbers } from '@/api/contract/index';
|
||||
import { BiddingImportExcelFile, getTreeLimit, biddingLimitListUpdate, sheetList } from '@/api/bidding/biddingLimit';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const userStore = useUserStoreHook();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const queryForm = ref({
|
||||
versions: '',
|
||||
sheet: ''
|
||||
const dialogVisible = ref(false);
|
||||
const row = ref<any>();
|
||||
const planType = ref<any>('');
|
||||
const fileUploadRef = ref<any>();
|
||||
const ruleForm = ref<any>();
|
||||
const rules = ref({
|
||||
costEstimationFile: [{ required: true, message: '请上传招标文件', trigger: ['blur'] }]
|
||||
});
|
||||
const loading = ref(false);
|
||||
const options = ref<any[]>([]);
|
||||
const sheets = ref<any[]>([]);
|
||||
const tableData = ref<any[]>([]);
|
||||
const isExpandAll = ref(true);
|
||||
// 接受父组件传递的参数
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
const emit = defineEmits(['success']);
|
||||
const form = ref({
|
||||
costEstimationFile: ''
|
||||
});
|
||||
|
||||
//获取版本号
|
||||
const getVersionNums = async () => {
|
||||
try {
|
||||
const params = {
|
||||
projectId: currentProject.value?.id,
|
||||
pageSize: 1000,
|
||||
pageNum: 1
|
||||
};
|
||||
|
||||
const res = await obtainAllVersionNumbers(params);
|
||||
if (res.code == 200) {
|
||||
options.value = res.data;
|
||||
if (res.data.length > 0) {
|
||||
queryForm.value.versions = res.data[0];
|
||||
getSheetName();
|
||||
} else {
|
||||
queryForm.value.versions = '';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
const open = (rows: any, type: string) => {
|
||||
dialogVisible.value = true;
|
||||
console.log(rows, type);
|
||||
row.value = rows;
|
||||
planType.value = type;
|
||||
};
|
||||
//选择版本号
|
||||
const changeVersions = () => {
|
||||
getSheetName();
|
||||
const closeDialog = () => {
|
||||
dialogVisible.value = false;
|
||||
form.value.costEstimationFile = '';
|
||||
emit('success');
|
||||
};
|
||||
|
||||
//选择表名
|
||||
const changeSheet = () => {
|
||||
getTableData();
|
||||
};
|
||||
|
||||
//获取表名
|
||||
const getSheetName = async () => {
|
||||
try {
|
||||
const params = {
|
||||
projectId: currentProject.value?.id
|
||||
// versions: queryForm.value.versions
|
||||
};
|
||||
const res = await sheetList(params);
|
||||
if (res.code == 200) {
|
||||
sheets.value = res.data;
|
||||
if (res.data.length > 0) {
|
||||
queryForm.value.sheet = res.data[0];
|
||||
} else {
|
||||
queryForm.value.sheet = '';
|
||||
}
|
||||
getTableData();
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
//获取表格
|
||||
const getTableData = async () => {
|
||||
loading.value = true;
|
||||
const params = {
|
||||
projectId: currentProject.value?.id,
|
||||
sheet: queryForm.value.sheet,
|
||||
type: props.type
|
||||
};
|
||||
const res = await getTreeLimit(params);
|
||||
loading.value = false;
|
||||
if (res.code == 200) {
|
||||
tableData.value = [res.data[0]];
|
||||
}
|
||||
console.log(loading.value);
|
||||
};
|
||||
//修改单价
|
||||
const handleSave = (row: any) => {
|
||||
try {
|
||||
if (!row.unitPrice) {
|
||||
const submitForm = () => {
|
||||
fileUploadRef.value.submitUpload().then((res) => {
|
||||
if (res == 'noFile') {
|
||||
ElMessage({
|
||||
message: '请输入单价',
|
||||
message: '请上传招标文件',
|
||||
type: 'warning'
|
||||
});
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
biddingLimitListUpdate(row).then((res) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage({
|
||||
message: '修改成功',
|
||||
type: 'success'
|
||||
});
|
||||
getTableData();
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
ElMessage({
|
||||
message: '修改失败',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
};
|
||||
const tableRef = ref<any>();
|
||||
|
||||
const toggleExpandAll = () => {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
console.log(isExpandAll.value);
|
||||
|
||||
tableData.value.forEach((row) => {
|
||||
tableRef.value.toggleRowExpansion(row, isExpandAll.value);
|
||||
dialogVisible.value = false;
|
||||
emit('success');
|
||||
});
|
||||
};
|
||||
//导入
|
||||
const importExcel = (options: any): any => {
|
||||
let formData = new FormData();
|
||||
formData.append('file', options.file);
|
||||
loading.value = true;
|
||||
BiddingImportExcelFile({ projectId: currentProject.value?.id }, formData)
|
||||
.then((res) => {
|
||||
const { code } = res;
|
||||
if (code == 200) {
|
||||
proxy.$modal.msgSuccess(res.msg || '导入成功');
|
||||
getTableData();
|
||||
}
|
||||
})
|
||||
.catch((err) => {})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
getVersionNums();
|
||||
}
|
||||
);
|
||||
const handleExport = () => {
|
||||
proxy?.download(
|
||||
'/bidding/biddingLimitList/export',
|
||||
{
|
||||
projectId: currentProject.value?.id,
|
||||
sheet: queryForm.value.sheet
|
||||
},
|
||||
`限价一览表${queryForm.value.sheet}.xlsx`
|
||||
);
|
||||
};
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
onMounted(() => {
|
||||
getSheetName();
|
||||
defineExpose({
|
||||
open
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped lang="scss"></style>
|
||||
|
99
src/views/tender/plan/comm/winTheBid.vue
Normal file
99
src/views/tender/plan/comm/winTheBid.vue
Normal file
@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<el-dialog v-model="dialogVisible" title="中标文件" width="500" draggable>
|
||||
<el-form ref="ruleFormRef" style="max-width: 600px" :model="form" :rules="rules" label-width="auto">
|
||||
<el-form-item label="中标单位" prop="winningBidder">
|
||||
<el-select v-model="form.winningBidder" filterable placeholder="请选择单位" style="width: 240px">
|
||||
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="招标文件" prop="name">
|
||||
<file-upload
|
||||
v-model="form.costEstimationFile"
|
||||
:fileSize="100"
|
||||
:auto-upload="false"
|
||||
uploadUrl="/tender/biddingPlan/uploadBiddingDocuments"
|
||||
method="put"
|
||||
ref="fileUploadRef"
|
||||
:data="{
|
||||
projectId: currentProject?.id,
|
||||
type: planType,
|
||||
fileType: '0',
|
||||
bidStatus: '0',
|
||||
id: row.id,
|
||||
winningBidderId: form.winningBidder
|
||||
}"
|
||||
showFileList
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="closeDialog()"> 取消 </el-button>
|
||||
<el-button type="primary" @click="submitForm()">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { getUnitList } from '@/api/tender/index';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
const userStore = useUserStoreHook();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const dialogVisible = ref(false);
|
||||
const row = ref<any>();
|
||||
const planType = ref<any>('');
|
||||
const fileUploadRef = ref<any>();
|
||||
const ruleForm = ref<any>();
|
||||
const options = ref<any>([]);
|
||||
const rules = ref({
|
||||
costEstimationFile: [{ required: true, message: '请上传招标文件', trigger: ['blur'] }]
|
||||
});
|
||||
const emit = defineEmits(['success']);
|
||||
const form = ref({
|
||||
costEstimationFile: '',
|
||||
winningBidder: ''
|
||||
});
|
||||
const open = (rows: any, type: string) => {
|
||||
dialogVisible.value = true;
|
||||
console.log(rows, type);
|
||||
row.value = rows;
|
||||
planType.value = type;
|
||||
getUnitListData();
|
||||
};
|
||||
const getUnitListData = async () => {
|
||||
let res = await getUnitList({
|
||||
projectId: currentProject.value?.id
|
||||
});
|
||||
if (res.code == 200) {
|
||||
options.value = res.data.map((item: any) => {
|
||||
return {
|
||||
label: item.supplierName,
|
||||
value: item.id
|
||||
};
|
||||
});
|
||||
}
|
||||
console.log(res);
|
||||
};
|
||||
const closeDialog = () => {
|
||||
dialogVisible.value = false;
|
||||
form.value.winningBidder = '';
|
||||
emit('success');
|
||||
};
|
||||
const submitForm = () => {
|
||||
fileUploadRef.value.submitUpload().then((res) => {
|
||||
if (res == 'noFile') {
|
||||
ElMessage({
|
||||
message: '请上传招标文件',
|
||||
type: 'warning'
|
||||
});
|
||||
return;
|
||||
}
|
||||
closeDialog();
|
||||
emit('success');
|
||||
});
|
||||
};
|
||||
defineExpose({
|
||||
open
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
@ -189,7 +189,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"
|
||||
@ -203,16 +204,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>
|
||||
@ -266,6 +287,9 @@ import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { getDicts } from '@/api/system/dict/data';
|
||||
import { Plus } from '@element-plus/icons-vue';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import winTheBid from './comm/winTheBid.vue';
|
||||
import information from './comm/planPage.vue';
|
||||
|
||||
import {
|
||||
sheetList,
|
||||
tenderPlanList,
|
||||
@ -279,7 +303,6 @@ import {
|
||||
delBiddView,
|
||||
editStatus
|
||||
} from '@/api/tender/index';
|
||||
import { it } from 'element-plus/es/locale/index.mjs';
|
||||
|
||||
const userStore = useUserStoreHook();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
|
@ -275,6 +275,7 @@
|
||||
<el-row class="mb-4">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="入库资料" prop="inputFile">
|
||||
<template #label> <span class="text-red">*</span> 入库资料 </template>
|
||||
<file-upload
|
||||
v-model="form.inputFile"
|
||||
:fileType="['doc', 'docx', 'pdf']"
|
||||
|
@ -4,11 +4,11 @@
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item>
|
||||
<!-- <el-form-item>
|
||||
<el-badge :value="userSelectCount" :max="10" class="item">
|
||||
<el-button type="primary" @click="openUserSelect">选择申请人</el-button>
|
||||
</el-badge>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="任务名称" prop="nodeName">
|
||||
<el-input v-model="queryParams.nodeName" placeholder="请输入任务名称" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
|
230
vite.config.ts.timestamp-1756395377501-e6f009967ecc8.mjs
Normal file
230
vite.config.ts.timestamp-1756395377501-e6f009967ecc8.mjs
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user